Problem B. Milk Tea Google Kickstart Round E 2018

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yixin94/article/details/82226462

题意:给定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;
}

猜你喜欢

转载自blog.csdn.net/yixin94/article/details/82226462