1. 程式人生 > >2017.10.28 QB模擬賽 —— 下午

2017.10.28 QB模擬賽 —— 下午

+= card closed 技術分享 oot long sum car one

題目鏈接

T1

按x值排序

遇到第二種牌插入 遇到第一種牌 查詢<=y 的最小值 刪除他

splay multiset

cys大佬說 multiset就是不去重的set,

技術分享
#include <algorithm>
#include <cstdio>
#define N 100005
using namespace std;

struct node
{
    int x,y,opt;
    bool operator<(node a)const
    {
        if(opt!=a.opt&&x==a.x) return
opt>a.opt; else return x<a.x; } }card[N<<1]; int n,ans,root,cn,siz[N],cnt[N],data[N],fa[N],ch[N][2]; inline void pushup(int rt) { int l=ch[rt][0],r=ch[rt][1]; siz[rt]=siz[l]+siz[r]+cnt[rt]; } inline void ins(int &rt,int x) { if(!rt) { rt
=++cn; data[cn]=x; siz[cn]=cnt[cn]=1; return; } if(data[rt]==x) { cnt[rt]++; siz[rt]++; return; } if(x<data[rt]) { ins(ch[rt][0],x); fa[ch[rt][0]]=rt; pushup(rt); } else { ins(ch[rt][
1],x); fa[ch[rt][1]]=rt; pushup(rt); } } int ask_pre(int rt,int x) { int p=rt,ret=0x7fffffff; while(p) { if(x<data[p]) p=ch[p][0]; else { ret=data[p]; p=ch[p][1]; } } return ret; } inline int son(int x) {return ch[fa[x]][1]==x;} void rotate(int x) { int y=fa[x],z=fa[y],b=son(x),c=son(y),a=ch[x][!b]; if(z) ch[z][c]=x; else root=x; fa[x]=z; if(a) fa[a]=y; ch[x][!b]=y;ch[y][b]=a; fa[y]=x; pushup(y);pushup(x); } void splay(int x,int i) { while(fa[x]!=i) { int y=fa[x],z=fa[y]; if(z==i) rotate(x); else { if(son(y)==son(x)) rotate(y),rotate(x); else rotate(x),rotate(x); } } } int getmn(int rt) { int ret=-1,p=rt; while(p) { ret=p; p=ch[p][0]; } return ret; } void del(int rt,int x) { if(data[rt]==x) { if(cnt[rt]>1) { cnt[rt]--; siz[rt]--; } else { splay(rt,0); int p=getmn(ch[rt][1]); if(p!=-1) { splay(p,rt); root=p;fa[p]=0; ch[p][0]=ch[rt][0]; fa[ch[rt][0]]=p; } else { root=ch[rt][0]; fa[ch[rt][0]]=0; } } return; } if(x<data[rt]) { del(ch[rt][0],x); pushup(rt); } else { del(ch[rt][1],x); pushup(rt); } } int main(int argc,char *argv[]) { freopen("water.in","r",stdin); freopen("water.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;++i) scanf("%d%d",&card[i].x,&card[i].y),card[i].opt=1; for(int i=n+1;i<=n<<1;++i) scanf("%d%d",&card[i].x,&card[i].y),card[i].opt=2; sort(card+1,card+1+n*2); for(int i=1;i<=n<<1;++i) { if(card[i].opt==2) ins(root,card[i].y); else { if(!cn) continue; int v=ask_pre(root,card[i].y); if(v==0x7fffffff) continue; ans++; del(root,v); } } printf("%d\n",ans); fclose(stdin); fclose(stdout); return 0; }
splay 技術分享
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <set>
using namespace std;
int n;
multiset <int> s;
struct node {int x,y;} a[100005],b[100005];
int cmp(node i,node j) {return i.x<j.x;}
int main()
{
    freopen("water.in","r",stdin);
    freopen("water.out","w",stdout);
    int T;
    T=1;
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d%d",&a[i].x,&a[i].y);
        for(int i=0;i<n;i++) scanf("%d%d",&b[i].x,&b[i].y);
        sort(a,a+n,cmp);
        sort(b,b+n,cmp);
        s.clear();
        int k=0,ans=0;
        for(int i=0;i<n;i++)
        {
            while(a[i].x>=b[k].x&&k<n)
            {
                 s.insert(b[k].y);
                 k++;
            }
            if(s.empty())continue;
            multiset<int>::iterator it=s.upper_bound(a[i].y);
            if (it==s.begin()) continue; it--;
            ans++; s.erase(it);
        }
        printf("%d\n",ans);
    }
    return 0;
}
multiset

T2

最少需要 log(n)/log(2) 個

dp[j][k] 表示 金幣和是 j 最大金幣是k 的方案總數

枚舉下一枚金幣是什麽

技術分享
#include <cstdio>
#include <cmath>
#define N 1005

inline int min(int a,int b) {return a>b?b:a;}
int n,s,ans,f[N][N],dp[N][N];
int main(int argc,char *argv[])
{
    freopen("dream.in","r",stdin);
    freopen("dream.out","w",stdout);
    scanf("%d",&n);
    s=log2(n)+1;
    f[1][1]=1;
    for(int i=1;i<s;++i)
    {
        for(int j=1;j<=n;++j)
         for(int k=1;k<=n;++k)
          if(f[j][k])
           for(int l=k+1;l<=j+1;++l)
            dp[min(n,j+l)][l]+=f[j][k];
        for(int j=1;j<=n;++j)
         for(int k=1;k<=n;++k)
          f[j][k]=dp[j][k],dp[j][k]=0;
    }
    for(int i=1;i<=n;++i) ans+=f[n][i];
    printf("%d %d\n",s,ans);
    fclose(stdin); 
    fclose(stdout);
    return 0;
}
View Code


T3

dp[i][j] 表示 1~i 切了j刀的最優解

dp[i][j]=min{dp[k][j-1]+sum(k+1,i)}

從大到小 枚舉k 更新sum

復雜度 20*N^2

固定j,隨著i的增大,k不會減少

1d1d動態規劃優化

20*n^2的簡單dp -> 在固定j的情況下 隨著i的增大,k不降 -> 分治求dp值

技術分享
#include <cstdio>
#define N 100005
typedef long long LL;
int n,k,L,R,a[N],s[N];
LL sum,f[N],g[N];
void update(int x,int type)
{
    if(type==1) sum+=s[a[x]],++s[a[x]];
    else --s[a[x]],sum-=s[a[x]];
}
void move(int l,int r)
{
    while(l<L) update(--L,1);
    while(r>R) update(++R,1);
    while(l>L) update(L++,0);
    while(r<R) update(R--,0);
}
void work(int l,int r,int fl,int fr)
{
    if(fl>fr) return;
    int mid=(fl+fr)>>1,mi;
    LL mx=1LL<<60;
    for(int i=l;i<mid&&i<=r;++i)
    {
        move(i+1,mid);
        if(mx>f[i]+sum) mx=f[i]+sum,mi=i;
    }
    g[mid]=mx;
    work(l,mi,fl,mid-1);
    work(mi,r,mid+1,fr);
}
int main(int argc,char *argv[])
{
    freopen("dp.in","r",stdin);
    freopen("dp.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    f[0]=0;
    for(int i=1;i<=n;++i) f[i]=1LL<<60;
    while(k--)
    {
        L=1,R=0,sum=0;
        for(int i=1;i<=n;++i) s[i]=0;
        work(0,n-1,1,n);
        for(int i=0;i<=n;++i) f[i]=g[i],g[i]=0;
    }
    printf("%I64d\n",f[n]);
    fclose(stdin); fclose(stdout);
    return 0;
}
View Code

2017.10.28 QB模擬賽 —— 下午