zoukankan      html  css  js  c++  java
  • cf Round #764(Div. 3)

    C

    二分图匹配裸题。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=55,M=255;
    struct graph{
        int nxt,to;
    }e[M];
    int a[N],g[N<<1],fr[N<<1],cnt,n,t;
    bool u[N<<1];
    inline void adde(int x,int y){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline bool match(int x){
        for(int i=g[x];i;i=e[i].nxt)
            if(!u[e[i].to]){
                u[e[i].to]=true;
                if(!fr[e[i].to]||match(fr[e[i].to])){
                    fr[e[i].to]=x;return true;
                }
            }
        return false;
    }
    inline int hungary(){
        int ret=0;
    	memset(fr,0,sizeof(fr));
        for(int i=1;i<=n;i++){
            memset(u,0,sizeof(u));
            if(match(i)) ++ret;
        }
        return ret;
    }
    int main(){
    	int t;
    	scanf("%d",&t);
    	while(t--){
    		cnt=0;
    		memset(g,0,sizeof(g));
    		scanf("%d",&n);
    		for(int i=1;i<=n;++i){
    			scanf("%d",&a[i]);
    			while(a[i]){
    				if(a[i]<=n){
    					adde(i,a[i]+n);
    				}
    				a[i]/=2;
    			}
    		}
    		if(hungary()==n) printf("YES\n");
    		else printf("NO\n");
    	}
    	return 0;
    }
    

    D

    Description
    给定一个大小为n的字符串,把它们分给k个组(组不可以为空,但字符可以不分给任何组),组中字符要可以组成回文串,求最短字符串的最长长度。
    Solution

    解法一

    二分+贪心。
    贪心的时候,如果回文串长度为奇数,预先把最中间的字符取了(优先用总个数为奇数的字符,用总个数为偶数的字符时尽量集中)。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200005,M=30;
    int a[M],tot[M],n,k,t;
    char s[N];
    bool chk(int ans){
    	for(int i=0;i<26;++i) a[i]=tot[i];
    	
    	if(ans&1){
    		--ans;
    		int cnt=0;
    		for(int i=0;i<26;++i)
    			if(a[i]&1){
    				--a[i];
    				if(++cnt==k) break;
    			}
    		for(int i=0,d;i<26&&cnt<k;++i){
    			d=min(a[i],k-cnt);
    			a[i]-=d;cnt+=d;
    		}
    	}
    	
    	for(int i=1,len;i<=k;++i){
    		len=0;
    		for(int j=0,d;j<26;++j){
    			d=min(ans-len,a[j]);
    			if(d&1) --d;
    			len+=d;a[j]-=d;
    		}
    		if(len<ans) return false;
    	}
    	return true;
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d",&n,&k);
    		scanf("%s",s+1);
    		memset(tot,0,sizeof(tot));
    		for(int i=1;i<=n;++i){
    			++tot[s[i]-'a'];
    		}
    		int l=0,r=n,mid;
    		while(l<r){
    			mid=(l+r+1)>>1;
    			if(chk(mid)) l=mid;
    			else r=mid-1;
    		}
    		printf("%d\n",l); 
    	}
    }
    

    解法二

    直接贪心,记录下有多少对偶数字符以及有多少个奇数字符,偶数字符平均分成k份后的剩余部分当奇数字符用,答案为偶数字符平均分成k份后的结果(+1)。(是否+1取决于奇数字符够不够用)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=200005,M=30;
    int tot[M],n,k,t;
    char s[N];
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d",&n,&k);
    		scanf("%s",s+1);
    		memset(tot,0,sizeof(tot));
    		for(int i=1;i<=n;++i){
    			++tot[s[i]-'a'];
    		}
    		int odd=0,ans=0;
    		for(int i=0;i<26;++i){
    			ans+=tot[i]/2;
    			odd+=tot[i]%2;
    		}
    		if(odd+ans%k*2>=k) printf("%d\n",ans/k*2+1);
    		else printf("%d\n",ans/k*2);
    	}
    }
    

    E

    Description
    给定n个长度为m的数字串\(s_i\),求数字串\(s'\)切割成若干长度\(\geq2\)的段 (每段在某个\(s_i\)中出现过) 的一种切割方案。
    Solution
    显然,长度>4的段都可由长度为2或3的段组成。
    用桶记录所有长度为2或3的段出现的位置(每种只需要知道其中一个位置)。

    正着做DP

    f[i]表示前i个数字都已经匹配时,以i结尾的那个串的匹配位置。
    若f[i-2]存在且s'[i-1...i]可匹配,f[i]=s'[i-1...i]匹配的位置。
    若f[i-3]存在且s'[i-2...i]可匹配,f[i]=s'[i-2...i]匹配的位置。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    
    struct range{
    	int l,r,i;
    	void init(){
    		l=r=i=0;
    	}
    	void set(int _l,int _r,int _i){
    		l=_l;r=_r;i=_i;
    	}
    	void print(){
    		printf("%d %d %d\n",l,r,i);
    	}
    }f[N],f2[N],f3[N];
    int nxt[N],n,m,t;
    char s[N];
    int num(char x,char y,char z){
    	return (x-'0')*100+(y-'0')*10+z-'0';
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		for(int i=0;i<N;++i){
    			f[i].init();f2[i].init();f3[i].init();
    		}
    		
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;++i) {
    			scanf("%s",s+1);
    			for (int j=1;j<m;++j) {
    				f2[num('0',s[j],s[j+1])].set(j,j+1,i);
    				if(j+1<m) f3[num(s[j],s[j+1],s[j+2])].set(j,j+2,i);
    			}
    		}
    		scanf("%s",s+1);
    		
    		if(m==1){
    			printf("-1\n");
    			continue;
    		}
    		if(f2[num('0',s[1],s[2])].i){
    			f[2]=f2[num('0',s[1],s[2])];
    		}
    		if(m>=3&&f3[num(s[1],s[2],s[3])].i){
    			f[3]=f3[num(s[1],s[2],s[3])];
    		}
    		for(int i=4;i<=m;++i) {
    			if(f[i-2].i&&f2[num('0',s[i-1],s[i])].i)
    				f[i]=f2[num('0',s[i-1],s[i])];
    			else if(f[i-3].i&&f3[num(s[i-2],s[i-1],s[i])].i)
    				f[i]=f3[num(s[i-2],s[i-1],s[i])];
    		}
    		if(!f[m].i) printf("-1\n");
    		else{
    			int cnt=0;
    			for(int i=m;i;i-=(f[i].r-f[i].l+1)){
    				nxt[i-(f[i].r-f[i].l+1)]=i;
    				++cnt;
    			}
    			nxt[m]=m+1;
    			printf("%d\n",cnt);
    			for(int i=nxt[0];i<=m;i=nxt[i])
    				f[i].print();
    		}
    
    	}
    	return 0;
    }
    

    反着做DP

    f[i]表示第i~m个数字都已经匹配时,以i开头的那个串的匹配位置。
    若f[i+2]存在且s'[i...i+1]可匹配,f[i]=s'[i...i+1]匹配的位置。
    若f[i+3]存在且s'[i...i+2]可匹配,f[i]=s'[i...i+2]匹配的位置。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1005;
    
    struct range{
    	int l,r,i;
    	void init(){
    		l=r=i=0;
    	}
    	void set(int _l,int _r,int _i){
    		l=_l;r=_r;i=_i;
    	}
    	void print(){
    		printf("%d %d %d\n",l,r,i);
    	}
    }f[N],f2[N],f3[N];
    int nxt[N],n,m,t;
    char s[N];
    int num(char x,char y,char z){
    	return (x-'0')*100+(y-'0')*10+z-'0';
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		for(int i=0;i<N;++i){
    			f[i].init();f2[i].init();f3[i].init();
    		}
    		
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=n;++i) {
    			scanf("%s",s+1);
    			for (int j=1;j<m;++j) {
    				f2[num('0',s[j],s[j+1])].set(j,j+1,i);
    				if(j+1<m) f3[num(s[j],s[j+1],s[j+2])].set(j,j+2,i);
    			}
    		}
    		scanf("%s",s+1);
    		
    		if(m>=2&&f2[num('0',s[m-1],s[m])].i){
    			f[m-1]=f2[num('0',s[m-1],s[m])];
    		}
    		if(m>=3&&f3[num(s[m-2],s[m-1],s[m])].i){
    			f[m-2]=f3[num(s[m-2],s[m-1],s[m])];
    		}
    		for(int i=m-3;i>0;--i) {
    			if(f[i+2].i&&f2[num('0',s[i],s[i+1])].i)
    				f[i]=f2[num('0',s[i],s[i+1])];
    			else if(f[i+3].i&&f3[num(s[i],s[i+1],s[i+2])].i)
    				f[i]=f3[num(s[i],s[i+1],s[i+2])];
    		}
    		if(!f[1].i) printf("-1\n");
    		else{
    			int cnt=0;
    			for(int i=1;i<=m;i+=(f[i].r-f[i].l+1)) ++cnt;
    			printf("%d\n",cnt);
    			for(int i=1;i<=m;i+=(f[i].r-f[i].l+1))
    				f[i].print();
    		}
    
    	}
    	return 0;
    }
    

    F

    Description
    交互题,给定n,需要猜出x \((1\leq x<n)\)
    你可以询问+c,则x=x+c,返回\(\lfloor\frac{x}{n}\rfloor\)
    Solution
    构造出二分即可:对于需要验证的mid,我们取能够使\(x_0=mid\)时,\(x_0+\sum c_i=0\;(mod\;n)\)的c。

    #include<bits/stdc++.h>
    using namespace std;
    
    int main(){
    	int n,sc=0,ans;
    	scanf("%d",&n);
    	int l=1,r=n-1;
    	while(l<r){
    		int mid=(l+r+1)>>1;
    		int c=n-(sc+mid)%n;
    		sc+=c; 
    		printf("+ %d\n",c);fflush(stdout);
    		scanf("%d",&ans);
    		l=max(l,ans*n-sc);
    		r=min(r,ans*n-sc+n-1);
    	}
    	printf("! %d\n",l+sc);fflush(stdout);
    	return 0;
    }
    

    G

    Description
    求权值为 \(w_1|w_2|...|w_{n-1}\) 的最小生成树。
    Solution
    从高位到低位贪心,如果当前位可以为0则丢弃所有当前位为1的边。只要图还能连通就可以丢。

    #include<bits/stdc++.h>
    using namespace std;
    
    const int N=200005;
    struct edge{
    	int x,y,w;
    }e[N];
    int fa[N],n,m,t;
    bool b[N];
    int gf(int u){
    	if(u==fa[u]) return u;
    	return fa[u]=gf(fa[u]);
    }
    int main(){
    	scanf("%d",&t);
    	while(t--){
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;++i){
    			scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    		}
    		for(int i=1;i<=m;++i) b[i]=true;
    		int ans=0;
    		for(int k=30;k>=0;--k){
    			for(int i=1;i<=n;++i) fa[i]=i;
    			for(int i=1;i<=m;++i)
    				if(b[i]&&!(e[i].w&(1<<k))){
    					if(gf(e[i].x)!=gf(e[i].y)) fa[gf(e[i].x)]=gf(e[i].y);
    				}
    			bool flag=true;
    			for(int i=1;i<=n;++i)
    				if(gf(i)!=gf(1)){
    					flag=false;break;
    				}
    			if(flag){
    				for(int i=1;i<=m;++i)
    					if(e[i].w&(1<<k)) b[i]=false;
    			}
    			else ans|=(1<<k);
    		}
    		printf("%d\n",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    python使用suds来调用webservice
    第二章 :初识MySQL
    什么是端口概念?
    数据库中的五种约束
    MySQL基本概念以及简单操作
    Java 持久化操作之 --XML
    Soso(嗖嗖)移动 java 项目
    Java多线程笔记总结
    java中代码的注释和快捷
    java oop 单列 双列 集合, 迭代器 的使用和说明
  • 原文地址:https://www.cnblogs.com/AireenYe/p/15808546.html
Copyright © 2011-2022 走看看