2016"百度之星" - 复赛(Astar Round3) 题解 (待续)

D++游戏

众所周知,度度熊喜欢的字符只有两个:B 和D。

今天,它发明了一个游戏:D游戏。

度度熊的英文并不是很高明,所以这里的D,没什么高深的含义,只是代指等差数列(等差数列百科)中的公差D。

这个游戏是这样的,首先度度熊拥有一个公差集合{D},然后它依次写下N个数字排成一行。游戏规则很简单:

1.在当前剩下的有序数组中选择X(X≥2) 个连续数字;

2.检查1 选择的X个数字是否构成等差数列,且公差 d∈{D};

3.如果2满足,可以在数组中删除这X个数字;

4.重复 1−3 步,直到无法删除更多数字。
度度熊最多能删掉多少个数字,如果它足够聪明的话?

为了挑战自己,度度熊给D游戏多设了一个条件,Xmin和Xmax,在游戏的第一步,选出X个连续数字时,必须满足Xmin≤X≤Xmax。它称这个游戏为D++游戏。

同时精益求精的度度熊还希望知道删掉最多数字的最少步数。
1<=N,M<=32,1<=Xmin,Xmax<=16

考虑 dp[k][i][j] 为区间[i,j]上取完,且最后一次(取了头,若长度大于1则也取了尾)取了长度为k的等差数列的最小步数
ansi,j 为满足Xmin,Xmax约束时,区间[i,j]上取完的最小步数

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<cctype>
#include<ctime>
#include<iomanip> 
#include<vector>
#include<string>
#include<set> 
#include<queue>
#include<stack>
#include<map>
#include<sstream>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=pre[x];p;p=next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=next[p]) 
#define Lson (x<<1)
#define Rson ((x<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,63,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (1000007)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define Pr(kcase,ans) printf("Case #%d: %lld\n",kcase,ans);
#define PRi(a,n) For(i,n-1) cout<<a[i]<<' '; cout<<a[n]<<endl;
#define PRi2D(a,n,m) For(i,n) { \
                        For(j,m-1) cout<<a[i][j]<<' ';\
                        cout<<a[i][m]<<endl; \
                        } 
typedef long long ll;
ll mul(ll a,ll b){return (a*b)%F;}
ll add(ll a,ll b){return (a+b)%F;}
ll sub(ll a,ll b){return ((a-b)%F+F)%F;}
void upd(ll &a,ll b){a=(a%F+b%F)%F;}
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define MAXN (33)
int n,m,L,R;
int a[MAXN],dp[MAXN][MAXN][MAXN],ans[MAXN][MAXN];  
set<int> d;
bool ok[MAXN][MAXN];
pi res[MAXN];
int main()
{
// freopen("A.in","r",stdin);
// freopen(".out","w",stdout);
    int T=read();
    For(kcase,T) {
        printf("Case #%d:\n",kcase);
        n=read(); m=read(); L=read(); R=read();
        For(i,n) a[i]=read();
        d.clear();
        For(i,m) d.insert(read());

        For(i,n) Fork(j,i+1,n) ok[i][j]=!!d.count(a[j]-a[i]);
        MEMI(ans) MEMI(dp)
        For(len,n) For(i,n-len+1) {
            int j=i+len-1;
            For(k,R) {
                if (k>j-i+1) continue;
                if (i==j) dp[k][i][j]=1;  
                else if (k==1) dp[k][i][j]=1+ans[i+1][j];
                else {
                    if ((a[j]-a[i])%(k-1)) continue;
                    int d=(a[j]-a[i])/(k-1);
                    Fork(l,i+1,j) if (ok[i][l]&&a[l]-a[i]==d) {
                        dp[k][i][j]=min(dp[k][i][j], (i+1<=l-1)*ans[i+1][l-1] + dp[k-1][l][j] );
                    }
                }               
            }
            ans[i][j]=dp[L][i][j];
            Fork(k,L,R) ans[i][j]=min(ans[i][j], dp[k][i][j]);
            Fork(l,i,j-1) ans[i][j]=min(ans[i][j], ans[i][l] + ans[l+1][j]  );

        }

        res[0]=mp(0,0);
        For(i,n) {
            res[i]=res[i-1];
            Rep(j,i-1) 
                if (ans[j+1][i]<=n) 
                    res[i] = max(res[i],mp(res[j].fi+i-j,res[j].se-ans[j+1][i]));
        }
        cout<<res[n].fi<<' '<<-res[n].se<<endl; 


    }
    return 0;
}

K个联通块

众所周知,度度熊喜欢图,尤其是联通的图。

今天,它在图上又玩出了新花样,新高度。有一张无重边的无向图, 求有多少个边集,使得删掉边集里的边后,图里恰好有KKK个连通块。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<vector>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p]) 
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (1000000009)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
typedef long long ll;
typedef unsigned long long ull;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
int n,m,k; 

int lowbit(int x) {
    return x&(-x);
}
int f[1<<14],g[1<<14],h[1<<14],t[1<<14][14];
int ff[15][15];
#define MAXN (14+10) 
#define MAXM (10+1) 
int p2[100100];
void prework(int n) {
    p2[0]=1;
    For(i,n) p2[i]=(p2[i-1]<<1ll)%F;
}
int main()
{
// freopen("B.in","r",stdin);
// freopen(".out","w",stdout);
    int tt;
    cin>>tt;
    prework(100000);
    For(kcase,tt){
        printf("Case #%d:\n",kcase);
        scanf("%d%d%d",&n,&m,&k);
        MEM(ff) MEM(g) MEM(f) MEM(h) 
        Rep(i,1<<n) h[i]=0;
        int a,b;
        For(i,m) {
            a=read(),b=read();--a;--b;
            ff[a][b]=ff[b][a]=1;
        }

        int tot=1<<n;
        Rep(S,tot) {
            Rep(i,n)
                if (S&(1<<i)) {
                    Fork(j,i,n-1) {
                        if (S&(1<<j)) 
                            if (ff[i][j]) h[S]++; 
                    }
                }
        }
        Rep(S,tot) h[S]=p2[h[S]];       


        Rep(i,n) f[1<<i]=1,g[1<<i]=0;

        Rep(S,tot) {
            int Q=lowbit(S);
            for (int x = S-Q; x; x = (x-1)&(S-Q)) {
                if (!(S-x)) continue;
                g[S]+=1LL*f[S-x]*h[x]%F;
                g[S]%=F;
            }
            f[S]=h[S]-g[S];         
            f[S]%=F;
            if (f[S]<0) f[S]+=F;
            t[S][1]=f[S];
        }
        Fork(j,2,k) {
            Rep(S,tot) {
                t[S][j]=0;
                int Q=lowbit(S);
                for (int x = S-Q; x; x = (x-1)&(S-Q)) {
                     t[S][j]=(t[S][j]+1LL*t[x][j-1]*f[S-x]%F)%F;
                }
            }
        } 


        ll ans=t[tot-1][k]%F;
        printf("%d\n",(int)ans); 
    }


    return 0;
}

拍照

扫描线 模版题

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<vector>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p]) 
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
typedef long long ll;
typedef unsigned long long ull;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define MAXN (10000+10)
struct comm{
    int x,y,z,d;
}ask[MAXN];
struct comm2 {
    int x,c;
    comm2(int _x=0,int _c=0){
        x=_x,c=_c;
    }
    friend bool operator<(comm2 a,comm2 b) {
        if (a.x!=b.x) return a.x<b.x;
        return a.c>b.c;
    }
}went[MAXN*2],not_mov[MAXN*2];
int n,sz1,sz2;
vector<pi> v;
int main()
{
// freopen("C.in","r",stdin);
// freopen(".out","w",stdout);
    int T;
    cin>>T;
    For(kcase,T){
        v.erase(v.begin(),v.end());
        printf("Case #%d:\n",kcase);
        n=read();
        sz1=sz2=0;
        For(i,n) {
            ask[i].x=read(),ask[i].y=read(),ask[i].z=read(),ask[i].d=read();    
            if (ask[i].y-ask[i].x<=2*ask[i].z) {
                if (ask[i].d==-1) {
                    went[++sz1]=comm2(ask[i].y-ask[i].z,1);
                    went[++sz1]=comm2(ask[i].x+ask[i].z,-1);
                }
                else {
                    not_mov[++sz2]=comm2(ask[i].y-ask[i].z,1);
                    not_mov[++sz2]=comm2(ask[i].x+ask[i].z,-1);
                }
            }

        }
        sort(went+1,went+1+sz1);
        sort(not_mov+1,not_mov+1+sz2);
        int nowc=0;
        For(i,sz1) {
            if (went[i].c==1) nowc++;
            else {
                v.pb(mp(went[i].x,nowc));
                nowc--;
            }           
        }
        v.pb(mp(INF,0));
        int sz=v.size();
        RepD(i,sz-2) v[i].se=max(v[i].se,v[i+1].se);

        int ans=0;
        nowc=0;
        For(i,sz2) {
            if (not_mov[i].c==1) nowc++;

            int p=lower_bound(v.begin(),v.end(),mp(not_mov[i].x,0))->se;

            ans=max(ans,nowc+p);            

            if (not_mov[i].c==-1) nowc--;

        }
        cout<<ans<<endl;
    }

    return 0;
}

XOR 游戏

用字典树查找集合中Xor S最大的值
好几次遇到了

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<functional>
#include<iostream>
#include<cmath>
#include<vector>
#include<cctype>
#include<ctime>
using namespace std;
#define For(i,n) for(int i=1;i<=n;i++)
#define Fork(i,k,n) for(int i=k;i<=n;i++)
#define Rep(i,n) for(int i=0;i<n;i++)
#define ForD(i,n) for(int i=n;i;i--)
#define ForkD(i,k,n) for(int i=n;i>=k;i--)
#define RepD(i,n) for(int i=n;i>=0;i--)
#define Forp(x) for(int p=Pre[x];p;p=Next[p])
#define Forpiter(x) for(int &p=iter[x];p;p=Next[p]) 
#define Lson (o<<1)
#define Rson ((o<<1)+1)
#define MEM(a) memset(a,0,sizeof(a));
#define MEMI(a) memset(a,127,sizeof(a));
#define MEMi(a) memset(a,128,sizeof(a));
#define INF (2139062143)
#define F (100000007)
#define pb push_back
#define mp make_pair 
#define fi first
#define se second
#define vi vector<int> 
#define pi pair<int,int>
#define SI(a) ((a).size())
typedef long long ll;
typedef unsigned long long ull;
int read()
{
    int x=0,f=1; char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 
#define MAXNode 400000
#define Sigma_size 2
class Trie
{
public:
    int ch[MAXNode][Sigma_size];
    int v[MAXNode],siz;
    Trie(int _siz=0):siz(_siz){MEM(ch) MEM(v)}
    void mem(int _siz=0){siz=_siz; MEM(ch) MEM(v)   }
    int idx(char c){return c-'a';}
    void insert(int X,int val=0)
    {
        int u=0;
        for(int i=(1<<30);i;i>>=1)
        {
            int c=(X&i)>0;
            if (!ch[u][c])
            {
                ++siz;
                MEM(ch[siz]);
                ch[u][c]=siz;
            }
            u=ch[u][c];
            v[u]+=val;
        }

    }
    int find(int X)
    {
        int u=0,res=0;
        for(int i=(1<<30);i;i>>=1)
        {
            int c=(X&i)>0;
            if (v[ch[u][c^1]])
            {
                u=ch[u][c^1];
                res+=i;
            } else if (v[ch[u][c]])
            {
                u=ch[u][c];

            }
            else return 0;
        }
        return res;
    }

}T;
#define MAXN (10000+10) 
#define MAXM (10+1) 
int n,m,L;
ll f[MAXN][MAXM],a[MAXN],S[MAXN];
ll check(ll mid) {
    MEM(f)
    For(i,L) if (S[i]>=mid) f[i][1]=1;
    Fork(j,2,m) {
        For(i,j-1) {
            if (f[i][j-1]) T.insert(S[i],1);
        }
        Fork(i,j,n) {
            if (T.find(S[i])>=mid) f[i][j]=1;
            if (i-L>0&&f[i-L][j-1]) T.insert(S[i-L],-1);
            if (f[i][j-1]) T.insert(S[i],1);
        }
        Fork(i,n-L+1,n) {
            if (f[i][j-1]) T.insert(S[i],-1);
        }

    }
    return f[n][m];
}
int main()
{
// freopen("D.in","r",stdin);
// freopen(".out","w",stdout);
    int tt;
    T.mem();
    cin>>tt;S[0]=0;
    For(kcase,tt){
        printf("Case #%d:\n",kcase);
        cin>>n>>m>>L;
        For(i,n) {
            scanf("%I64d",&a[i]);
            S[i]=S[i-1]^a[i];
        }
        ll L=0,R=1<<30,ans=0;
        while(L<=R) {
            ll m=(L+R)/2; 
            if (check(m)) L=m+1,ans=m; 
            else R=m-1;
        } 
        cout<<ans<<endl;
    }


    return 0;
}

你可能感兴趣的:(2016"百度之星" - 复赛(Astar Round3) 题解 (待续))