CF 1070J Streets and Avenues in Berhattan

DP的数组f其实开得不够大,应该开200000,但是它在cf上就是过了...
题意是把一堆字母分别分配到行和列.
分析一下,答案实际上只和n行中和m列中每种字母分配的个数有关.而且答案只和"在行和列都出现的字母有关"
结论1:最优方案中如果答案不为0,那么存在一种最优方案,满足只有一种字母在行和列都出现,其他字母要么只在行出现,要么只在列出现
假设有两种字母,分别在行和列都出现了,那么就可以通过在行/列之间交换这两种字母使得只有一种字母在行和列中都出现,且答案变小
结论2:如果最优方案中答案不为0且存在一种字母在行和列中都出现,那么其他种类的字母一定都用完了.
假设其他种类的字母没有用完,那么拿没用完的其他种类的字母,替换在行和列中都出现的字母,就可以使答案变小.
有这两个结论,就可以写写背包进行判断了.

#include<cstdio>
#include<algorithm>
using namespace std;
char buf[200005];
void read(int *a){
    scanf("%s",buf);
    for(int i=0;buf[i]!='\0';++i)a[buf[i]-'A']++;
}
bool f[30005];
bool check0(int *a,int n,int m,int k){
    int lim=n<m?m:n;
    int ano=n+m-lim;
    for(int i=0;i<=k;++i)f[i]=0;
    f[0]=true;
    for(int i=0,sum=0;i<26;++i){
        if(a[i]==0)continue;
        sum+=a[i];
        for(int j=sum;j>=a[i];--j){
            f[j]|=f[j-a[i]];
        }
    }
    for(int i=lim;i<=k-ano;++i){
        if(f[i])return true;
    }
    return false;
}
long long check(int *a,int n,int m,int k,int tmp){
    int lim=n<m?n:m;
    int ano=n+m-lim;
    for(int i=0;i<=lim;++i)f[i]=0;
    f[0]=true;
    for(int i=0,sum=0;i<26;++i){
        if(a[i]==0)continue;
        sum+=a[i];
        for(int j=sum;j>=a[i];--j){
            f[j]|=f[j-a[i]];
        }
    }
    long long ans=1ll<<60;
    for(int i=0;i<=lim;++i){
        if(f[i]&&k-tmp-i<=ano&&(lim-i)+(ano-(k-tmp-i))<=tmp)ans=min(ans,(lim-i)*1ll*(ano-(k-tmp-i)));
    }
    return ans;
}
int main(){
    int t;scanf("%d",&t);
    while(t--){
        int n,m,k;scanf("%d%d%d",&n,&m,&k);
        int cnt[26];
        for(int i=0;i<26;++i)cnt[i]=0;
        read(cnt);
        if(check0(cnt,n,m,k))printf("0\n");
        else{
            long long ans=1ll<<60;
            for(int i=0;i<26;++i){
                int tmp=cnt[i];
                cnt[i]=0;
                ans=min(ans,check(cnt,n,m,k,tmp));
                cnt[i]=tmp;
            }
            printf("%lld\n",ans);
        }
    }    
    return 0;
}
posted @ 2018-11-02 15:52  liu_runda  阅读(187)  评论(0编辑  收藏
偶然想到可以用这样的字体藏一点想说的话,可是并没有什么想说的. 现在有了:文化课好难