• 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]!='';++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
    ");
            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
    ",ans);
            }
        }    
        return 0;
    }
    
  • 相关阅读:
    pytest之断言
    python之self
    python标准数据结构类型
    pytest之fixture
    python之继承和多态
    安卓UI自动化,pytest+UIautomator2+allure+jenkins
    airtest
    Python中单下划线开头的特性
    系统默认分配的共享内存太小,导致zabbix_server无法启动
    运行yum报错Error: Cannot retrieve metalink for repository: epel. Please verify its path and try again
  • 原文地址:https://www.cnblogs.com/liu-runda/p/9896685.html
Copyright © 2020-2023  润新知