cf训练2
Posted waing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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
",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
",ans);
}
}
return 0;
}
B
题解
我们发现如果字符串最左和最右的字符不同,那么一定可以有 irreducible anagram ,我们把首尾换一下就行。 如果相同,且字符种类大于等于三,我们找到最后一个与末尾字符不同的字符 $s[k] eq 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
",now);
}
return 0;
}
D
题解
(k=1) 时,我们逐个对比就行。
$ k eq 1$ 时,我们把咖啡按 (k/2) 的大小分组,逐组比较,把记得的咖啡打上标记,最后统计没有标记的数目就是答案,这样就可以做到 $ frac{2n^2} {k} $ 。
继续优化,我们发现先尝第一组,第二组,再尝第三组。相当于对比了一二组和二三组。不用清空记忆。那么我们把上面的方案改变顺序,连续品尝即可。先 $ 1quad 2 quad 3 ... n$ ,相当于问了$ 1,2 quad 2,3 quad 3,4quad ...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
";
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
";
fflush(stdout);
cout<<"? "<<i<<endl;
fflush(stdout);
cin>>s;
now=0;
}
}
if(fl) V.push_back(i);
cout<<"R
";
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
";
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;
}
以上是关于cf训练2的主要内容,如果未能解决你的问题,请参考以下文章