cf训练2

CF 616 div1

A

题解

\(k \geq m-1\) ,我们可以任意指定顺序,我们求每个方案的最大值即可。

\(k < m-1\) ,发现我们有 \(m - k\) 种可能,取最小值即可。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int read()
{
	int k=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=5005;
int n,m,k,T,a[N];
int main()
{
	for(T=read();T;T--)
	{
		n=read();m=read();k=read();
		for(int i=1;i<=n;i++)
			a[i]=read();
		if(k>=m-1)
		{
			int ans=0;
			for(int i=1;i<=m;i++)	
				ans=max(ans,max(a[i],a[n-m+i]));
			printf("%d\n",ans);
			continue;
		}
		else
		{
			int ans=0,x=m-1-k;
			for(int i=0;i<=k;i++)
			{
				int as=0x7fffffff;
				for(int j=i+1;j<=i+x+1;j++)
					as=min(as,max(a[j],a[n-m+j]));
//				cout<<as<<endl;
				ans=max(ans,as);
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}
			
	

B

题解

我们发现如果字符串最左和最右的字符不同,那么一定可以有 irreducible anagram ,我们把首尾换一下就行。 如果相同,且字符种类大于等于三,我们找到最后一个与末尾字符不同的字符 $s[k] \neq s[n] $ ,把 \(s[k]\) 的所有字符放在最前面,再放 \(s[n]\) 的所有字符,最后把剩余字符随意摆放,这样就的串就是Irreducible Anagrams 。

当字符种类小于三时,显然不存在 Irreducible Anagrams。

统计一下每个字符的前缀和就可以了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
int read()
{
	int k=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=200055;
int n,a,b,sum[N][26];
char s[N];
int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for(int i=1;i<=n;i++)
	{
		memcpy(sum[i],sum[i-1],sizeof(sum[i]));
		sum[i][s[i]-'a']++;
	}
	n=read();
	for(int i=1;i<=n;i++)
	{
		a=read();b=read();
		if(a==b) puts("Yes");
		else if(s[a]!=s[b]) puts("Yes");
		else 
		{
			int cnt=0;
			for(int j=0;j<26;j++)
				if(sum[b][j]-sum[a-1][j])
					cnt++;
			if(cnt>2) puts("Yes");
			else puts("No");
		}
	}
	return 0;
}

C

题解

首先,每一盏灯最多在两个集合里,如果在一个或不在集合里,对该灯的操作是确定的。

接下来重点讨论在两个集合的做法,发现,不管灯是亮的还是灭的,我们都只有两种操作方法,亮的:一个操作一个不操作,灭的:都操作或都不操作。

我们可以用并查集维护集合,\(1 - m\) 表示对集合操作,\(m+1 - 2m\) 表示对集合不操作,我们按顺序开灯,同时处理并查集的关系并计算答案。 细节见代码。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define ll long long
using namespace std;
int read()
{
	int k=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) k=k*10+c-'0';return k*f;
}
const int N=600055;
int n,m,a[N],fa[N],size[N],c[N][3],fl[N];
char s[N];
int find(int x)
{
	if(fa[x]==x) return x;
	return fa[x]=find(fa[x]);
}
int get(int x)
{
	int a=find(x),b=find(x+m);
	if(fl[a]) return size[a];
	if(fl[b]) return size[b];
	return min(size[a],size[b]);
}
int main()
{
	n=read();m=read();
	scanf("%s",s+1);
	for(int i=1;i<=n;i++)
		a[i]=s[i]-'0';
	for(int i=1;i<=m;i++)
	{
		int x=read();
		for(int j=1;j<=x;j++)
		{
			int y=read();
			c[y][++c[y][0]]=i;
		}
	}
	int now=0;
	for(int i=1;i<=m*2;i++)
		fa[i]=i,size[i]=(i<=m);
	for(int i=1;i<=n;i++)
	{
		if(c[i][0]==1)
		{
			now-=get(c[i][1]);
			if(a[i]) fl[find(c[i][1]+m)]=1;
			else fl[find(c[i][1])]=1;
			now+=get(c[i][1]);
		}
		else if(c[i][0]==2)
		{
			int x=find(c[i][1]),y=find(c[i][2]),z=find(c[i][1]+m),w=find(c[i][2]+m);
			if(!a[i]&&x!=w)
			{
				now-=get(c[i][1])+get(c[i][2]);
				if(w!=x) size[w]+=size[x];fl[w]|=fl[x];fa[x]=w;
				if(z!=y) size[z]+=size[y];fl[z]|=fl[y];fa[y]=z;
				now+=get(c[i][1]);
			}
			else if(a[i]&&x!=y)
			{
				now-=get(c[i][1])+get(c[i][2]);
				if(x!=y) size[y]+=size[x],fl[y]|=fl[x];fa[x]=y;
				if(z!=w) size[z]+=size[w],fl[z]|=fl[w];fa[w]=z;
				now+=get(c[i][1]);
			}
		}
		printf("%d\n",now);
	}
	return 0;
}

D

题解

\(k=1\) 时,我们逐个对比就行。

$ k \neq 1$ 时,我们把咖啡按 \(k/2\) 的大小分组,逐组比较,把记得的咖啡打上标记,最后统计没有标记的数目就是答案,这样就可以做到 $ \frac{2n^2} {k} $ 。

继续优化,我们发现先尝第一组,第二组,再尝第三组。相当于对比了一二组和二三组。不用清空记忆。那么我们把上面的方案改变顺序,连续品尝即可。先 $ 1\quad 2 \quad 3 ... n$ ,相当于问了$ 1,2 \quad 2,3 \quad 3,4\quad ...n-1,n$ ,再 $ 1 \quad 3 \quad ....n-1$ ,$ 2 \quad 4 \quad .... n$ ,每次问完一大组再清空。

询问次数 $ \frac{3n^2} {2k} $ 。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#define ll long long
using namespace std;
int read() {
	int k=0,f=1;
	char c=getchar();
	for(; !isdigit(c); c=getchar()) if(c=='-') f=-1;
	for(; isdigit(c); c=getchar()) k=k*10+c-'0';
	return k*f;
}
const int N=1550;
int n,m,cnt[N];
char s;
vector<int> V;
int main() {
	cin>>n>>m;
	fflush(stdout);
	if(m==1) {
		int now=0;
		for(now=1; now<=m+1&&now<=n; now++) {
			cout<<"? "<<now<<endl;
			fflush(stdout);
			cin>>s;
			if(s=='N') V.push_back(now);
		}
		cout<<"R\n";
		for(int i=now; i<=n; i++) {
			cout<<"? "<<i<<endl;
			fflush(stdout);
			cin>>s;
			int fl=1,now=0;
			for(int j=0; j<V.size(); j++) {
				now++;
				cout<<"? "<<V[j]<<endl;
				fflush(stdout);
				cin>>s;
				if(s=='Y') {
					fl=0;
					break;
				}
				if(now==m) {
					cout<<"R\n";
					fflush(stdout);
					cout<<"? "<<i<<endl;
					fflush(stdout);
					cin>>s;
					now=0;
				}
			}
			if(fl) V.push_back(i);
			cout<<"R\n";
			fflush(stdout);
		}
		cout<<"! "<<V.size()<<endl;
		fflush(stdout);
	} else {
		int si=m/2,bl=n/si;
		for(int i=1; i<bl; i++)
			for(int j=1; j<=i&&j+i<=bl; j++) {
				cout<<"R\n";
				for(int k=j; k<=bl; k+=i)
					for(int p=(k-1)*si+1; p<=k*si; p++)	 {
						cout<<"? "<<p<<endl;
						fflush(stdout);
						cin>>s;
						if(s=='Y') cnt[p]=1;
					}
			}
		int ans=0;
		for(int i=1; i<=n; i++)
			if(!cnt[i]) ans++;
		cout<<"! "<<ans<<endl;
	}
	return 0;
}
posted @ 2020-02-05 16:05  waing  阅读(268)  评论(0编辑  收藏  举报