1. 程式人生 > >Problem B. Milk Tea Google Kickstart Round E 2018

Problem B. Milk Tea Google Kickstart Round E 2018

題意:給定N個二進位制數,求出一個二進位制數使得其和N個二進位制數的complaint之和最小。complaint=不相同的bit的個數。另外有M個constraint,求出的二進位制數不能出現在constraint中。

如果沒有constraint,最優解opt貪心即可求出來。假設sum[p]是N個二進位制數bit p的1的個數之和,那麼opt[p]=max(sum[p],N-sum[p])。

入手點是M<100,開始認為是從opt貪心,列舉改變一個bit,改變兩個bit,...直到不出現在constraint中。如果改變一個bit,直接貪心找到complaint最大的一個bit取反即可。但是如果改變兩個bit,只能用搜索了,因為給定一個數組x1,x2,x3,x4,x5,(e.g., 5, 4, 3, 2, 1) 如果從x1開始列舉,可能滿足constraint的組合裡x1+x5滿足條件,但是有可能x2+x3 complaint更大。所以感覺還是要列舉2^p個組合。。。

也想過按照bit DP,但是當時覺得前p個bit滿足constraint這個不好弄,因為constraint是個global的東西。。真是行百里者半九十。

正解是按照bit構造。因為只有M個constraint,所以只要找到complaint最小的前M+1個二進位制數,一定有一個是符合條件的。假設s[0,...,p+1]是前M+1個,那麼s[0,..,p]一定也是前M+1個。Proof by contradiction: 如果s[0,...,p+1]是前M+1個而s[0,...,p]不是,假設s[p+1]增加的complaint是x,那麼排在s[0,...,p]之前的s'[0,...,p]增加一個相同的bit (s[p+1]),構成的新的二進位制數的complaint一定比s[0,...,p+1]小,如此可以產生多餘M+1個complaint比s[0,..,p+1]小的二進位制數,和s[p+1]是前M+1個矛盾。

Then 如果s[0,...,p]不是前M+1個,s[0,..,p+1]一定也不是前M+1個,無論新增的Bit是0 or 1.所以對於每個bit p,維護前M個s[0,..,p],對下一個bit增加0 or 1,再對bit p+1排序找出前M+1個……

可以預處理求出N個二進位制數bit p的1的個數之和,這樣從bit p to bit p+1可以O(1)求出新增的complaint。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;

const int maxn=5010;
int T;
int N;
int K;
int A[maxn];
int ans;
int vis[maxn];
int main()
{
//    freopen("input.txt","r",stdin);
    freopen("A-large.in","r",stdin);
    freopen("A.txt","w",stdout);
    clock_t START_TIME;
    clock_t FINISH_TIME;
    START_TIME=clock();
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        memset(A,0,sizeof(A));
        memset(vis,0,sizeof(vis));
        scanf("%d %d",&N,&K);
        ans=0;
        for(int i=0;i<N;i++)
        {
            scanf("%d",&A[i]);
        }
        sort(A,A+N);
        int idx=0;
        for(int i=0;i<N;i++)
        {
            int cnt=0;
            while(cnt<K)
            {
                if(vis[idx]==1)
                {
                    idx++;
                }
                else if(A[idx]-i-1<0)
                {
                    idx++;
                }
                else
                {
                    cnt++;
                    vis[idx++]=1;
                    ans++;
                }
                if(idx>=N)
                {
                    break;
                }
            }
            if(idx>=N)
            {
                break;
            }
        }
        printf("Case #%d: %d\n",ca,ans);
        cerr<<"finish case "<<ca<<endl;

    }

    FINISH_TIME=clock();
    cerr<<1.0*(FINISH_TIME-START_TIME)/CLOCKS_PER_SEC <<" (s) "<<endl;
    return 0;
}

附暴力code。。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string>
#include<cmath>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;



const int maxn=110;
int T;
int N;
int M;
int P;
int mp[maxn][maxn];
int sp[maxn][maxn];
int opt[maxn];
int colsum[maxn];
int arr[maxn];
int complaint[maxn];
int tmparr[maxn];
int ans;
bool cmp(int a,int b)
{
    return complaint[a]>complaint[b];
}
bool check()
{
    for(int i=0;i<M;i++)
    {
        bool flg2=true;
        for(int j=0;j<P;j++)
        {
            if(opt[j]!=sp[i][j])
            {
                flg2=false;
                break;
            }
        }
        if(flg2==true)
        {
            return true;//exist the same one
        }
    }
    return false;
}
bool checktmp()
{
    for(int i=0;i<M;i++)
    {
        bool flg2=true;
        for(int j=0;j<P;j++)
        {
            if(tmparr[j]!=sp[i][j])
            {
                flg2=false;
                break;
            }
        }
        if(flg2==true)
        {
            return true;//exist the same one
        }
    }
    return false;
}
void dfs(int n)
{
    if(n==P)
    {
//        for(int i=0;i<P;i++)
//        {
//            cout<<tmparr[i]<<" ";
//        }
//        cout<<endl;
//        return;
        if(checktmp()==true)
        {
//            cout<<"existing ";
//            for(int i=0;i<P;i++)
//            {
//                cout<<tmparr[i]<<" ";
//            }
//            cout<<endl;
            return;
        }
        else
        {
            int tmp=0;
            for(int j=0;j<P;j++)
            {
                if(tmparr[j]!=opt[j])
                {
                    tmp+=max(colsum[j],N-colsum[j]);
                }
                else
                {
                    tmp+=min(colsum[j],N-colsum[j]);
                }
            }
//            for(int i=0;i<P;i++)
//            {
//                cout<<tmparr[i]<<" ";
//            }
//            cout<<endl;
//            cout<<tmp<<endl;
            ans=min(ans,tmp);
        }
        return;
    }
    tmparr[n]=0;
    dfs(n+1);
    tmparr[n]=1;
    dfs(n+1);
    tmparr[n]=0;
    return;
}
int main()
{

//    freopen("input.txt","r",stdin);
    freopen("B-small-attempt0.in","r",stdin);
    freopen("B-small.txt","w",stdout);
    clock_t START_TIME;
    clock_t FINISH_TIME;
    START_TIME=clock();
    scanf("%d",&T);
    for(int ca=1;ca<=T;ca++)
    {
        memset(mp,0,sizeof(mp));
        memset(sp,0,sizeof(sp));
        memset(opt,0,sizeof(opt));
        memset(colsum,0,sizeof(colsum));
        memset(arr,0,sizeof(arr));
        memset(complaint,0,sizeof(complaint));
        memset(tmparr,0,sizeof(tmparr));
        ans=0x3f3f3f3f;
        scanf("%d %d %d",&N,&M,&P);
        for(int i=0;i<N;i++)
        {
            char tmp[maxn];
            scanf("%s",&tmp);
            for(int j=0;j<P;j++)
            {
                mp[i][j]=tmp[j]-'0';
//                scanf("%d",&);
//                cout<<mp[i][j]<<" ";
            }
//            cout<<endl;
        }
        for(int i=0;i<M;i++)
        {
            char tmp[maxn];
            scanf("%s",&tmp);
            for(int j=0;j<P;j++)
            {
                sp[i][j]=tmp[j]-'0';
//                scanf("%d",&sp[i][j]);
//                cout<<sp[i][j]<<" ";
            }
//            cout<<endl;
        }
        for(int j=0;j<P;j++)
        {
            for(int i=0;i<N;i++)
            {
                colsum[j]+=mp[i][j];
            }
            if(colsum[j]*2<=N)
            {
                opt[j]=0;
            }
            else
            {
                opt[j]=1;
            }
//            arr[j]=j;
//            complaint[j]=min(colsum[j],N-colsum[j]);
        }
//        for(int j=0;j<P;j++)
//        {
//            cout<<colsum[j]<<" ";
//        }
//        cout<<endl;
//        for(int j=0;j<P;j++)
//        {
//            cout<<opt[j]<<" ";
//        }
//        cout<<endl;
//        cout<<"dfs"<<endl;
        dfs(0);
//        sort(arr,arr+P,cmp);
//        for(int i=0;i<P;i++)
//        {
//            if(ckeck()==true)
//            {
//
//            }
//        }
        printf("Case #%d: %d\n",ca,ans);
        cerr<<"finish case "<<ca<<endl;

    }

    FINISH_TIME=clock();
    cerr<<1.0*(FINISH_TIME-START_TIME)/CLOCKS_PER_SEC <<" (s) "<<endl;
    return 0;
}