zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    移植stemwin笔记01 emwin文档说明
    emwin笔记
    stm32ucosiii 笔记03
    stm32操作系统ucosiii笔记02
    ucosiii笔记01
    keil4与proteus联机调试
    计算机网络一:OSI七层、TCP/IP五层与TCP/IP四层
    数据结构-概述
    RS232、RS485和RS422
    UART串口通讯协议
  • 原文地址:https://www.cnblogs.com/liu-runda/p/9896685.html
Copyright © 2011-2022 走看看