【CF套题】Educational Codeforces Round 57

版权声明:这是蒟蒻的BLOG,神犇转载也要吱一声哦~ https://blog.csdn.net/Dream_Lolita/article/details/85339864

【前言】
打了小号,做到心态爆炸,虽然最后过了6T。
然而十分后悔为什么没有用大号打,大号打就上橙了qwq。

【题目】
原题地址

A.Find Divisible

输出 l l 2 l 2l 即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("A.in","r",stdin);
	freopen("A.out","w",stdout);
#endif
	int T=read();
	while(T--)
	{
		int l=read(),r=read();
		printf("%d %d\n",l,l*2);
	}

	return 0;
}

B.Substring Removal

先找出前后相同字符能扩展到的位置,然后根据首尾字符是否相同进行计算即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,mod=998244353;
const int N=2e5+10;
ll n,l,r;
char s[N];

int main()
{
#ifndef ONLINE_JUDGE
	freopen("B.in","r",stdin);
	freopen("B.out","w",stdout);
#endif
	scanf("%d%s",&n,s);
	for(l=1;l<n && s[l]==s[0];l++);
	for(r=n-2;~r && s[r]==s[n-1];r--);r=n-r-1;
	if(s[0]==s[n-1])printf("%lld\n",(l+1)*(r+1)%mod);
	else printf("%lld\n",l+r+1);

	return 0;
}

C.Polygon for the Angle

我们作这个正 n n 边形的外接圆,那么可以得到对应圆心角的度数为 2 x 2x ,暴力枚举 n n 判断即可。注意判 x &gt; 90 x&gt;90 的情况特殊处理。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("C.in","r",stdin);
	freopen("C.out","w",stdout);
#endif
	int T=read();
	while(T--)
	{
		int x=read()*2;
		for(int i=3;i<=360;i++) 
			if(!(i*x%360) && (360/i!=(360-x))) {printf("%d\n",i);break;}
	}	
	return 0;
}

D.Easy Problem

f i , j f_{i,j} 表示前 i i 个字符匹配到第 j j 个的最小花费 DP \text{DP} 即可。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+10;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n;
char s[N];
ll a[N],f[N][6];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int id(char x)
{
	if(x=='h') return 1;
	else if(x=='a') return 2;
	else if(x=='r') return 3;
	else if(x=='d') return 4;
	return 0;
}

void gmin(ll &x,ll y){if(y<x)x=y;}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("D.in","r",stdin);
	freopen("D.out","w",stdout);
#endif
	n=read();scanf("%s",s+1);
	for(int i=1;i<=n;++i) a[i]=read();
	memset(f,0x3f3f,sizeof(f));f[0][0]=0;
	int flag=0;
	for(int i=1;i<=n;++i)
	{
		int x=id(s[i]);
		//printf("%d\n",x);
		if(!x) 
		{
			memcpy(f[i],f[i-1],sizeof(f[i-1]));
			continue; 
		}
		flag|=(1<<x-1);
		gmin(f[i][x],f[i-1][x-1]);
		gmin(f[i][x],f[i-1][x]);
		gmin(f[i][x-1],f[i-1][x-1]+a[i]);
		for(int j=0;j<x-1;++j) gmin(f[i][j],f[i-1][j]);
		for(int j=x+1;j<=4;++j)  gmin(f[i][j],f[i-1][j]);
	}

	if(flag^15){puts("0");return 0;}
	ll ans=INF; 
	//for(int j=1;j<=n;++j,puts(""))for(int i=0;i<=4;++i) printf("%lld ",f[j][i]);
	for(int i=0;i<4;++i) ans=min(ans,f[n][i]);
	printf("%lld\n",ans);

	return 0;
}

E.The Top Scorer

考虑枚举第一个人的权通过概率的定义进行计算,又由于存在权值相同的情况,我们需要枚举有多少个人的权与第一个人相同。现在问题就转化为有若干个人的权和为某个值,且都小于某个值的方案数。而这个问题同样可以通过枚举有多少个人等于最大值然后容斥进行计算。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=5500,mod=998244353;
int r,p,s,ans;
int C[N][N];

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}
int qpow(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=(ll)x*x%mod) if(y&1) res=(ll)res*x%mod;
	return res;
}
int up(int &x,int y){x+=y;if(x>=mod)x-=mod;if(x<0)x+=mod;}
int upm(int x){return x>=mod?x-mod:x;}
void initC()
{
	for(int i=0;i<N;++i)
	{
		C[i][0]=C[i][i]=1;
		for(int j=1;j<i;++j) C[i][j]=upm(C[i-1][j]+C[i-1][j-1]); 
	}
}
int solve(int n,int k,int s)
{
	if(!n) return !s;
	int res=0;
	for(int i=0;i<=n && i*(k+1)<=s;++i)
		up(res,(ll)(i&1?-1:1)*C[n+s-i*(k+1)-1][n-1]*C[n][i]%mod);
	return res;
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("E.in","r",stdin);
	freopen("E.out","w",stdout);
#endif
	initC();
	scanf("%d%d%d",&p,&s,&r);
	for(int i=r;i<=s;++i) for(int j=1;j<=p && i*j<=s;++j)//max&&the_same_as_max
		up(ans,(ll)qpow(j,mod-2)*solve(p-j,i-1,s-i*j)%mod*C[p-1][j-1]%mod);
	printf("%d\n",(ll)ans*qpow(C[p+s-r-1][p-1],mod-2)%mod);
	return 0;
}

F.Inversion Expectation

已知数字之间的逆序对贡献可以直接计算。
1 -1 之间的贡献相当于长度为 l e n len 序列的个数的期望逆序对。
在每个已知数字处统计前后的 1 -1 对其贡献即可。

#include<bits/stdc++.h>
#define lowbit(x) (x&(-x))
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f,N=2e5+10;
const int mod=998244353;
int n,aft,bef,cnt,c[N],a[N],sm[N];
ll ans;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int qpow(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod; 
	return res;
}

void update(int x,int v){for(;x<N;x+=lowbit(x))c[x]+=v;}
int query(int x){int ret=0;for(;x;x-=lowbit(x))ret+=c[x];return ret;}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("F.in","r",stdin);
	freopen("F.out","w",stdout);
#endif
	n=read();
	for(int i=1;i<=n;++i) 
	{
		a[i]=read();
		if(a[i]==-1) ++cnt;
	}
	ans=(ll)(cnt)*(cnt-1)%mod*qpow(4,mod-2)%mod;
	for(int i=1;i<=n;++i) if(~a[i]) ans+=query(n)-query(a[i]),update(a[i],1);
	ll inv=qpow(cnt,mod-2),ncnt=0;
	for(int i=1;i<=n;++i)
	{
		if(~a[i])
		{
			ll cnt1=(n-a[i])-(query(n)-query(a[i]));
			ll cnt2=cnt-cnt1;
			ans=(ans+cnt1*ncnt%mod*inv%mod)%mod;
			ans=(ans+cnt2*(cnt-ncnt)%mod*inv%mod)%mod;
		}
		else ++ncnt;
	}
	printf("%lld\n",(ans%mod+mod)%mod);

	return 0;
}

G.Lucky Tickets

写出数字的生成函数,那么它的 n 2 \frac n 2 次方每位对应的系数就是和为该次数的方案数,方案数平方一下就是答案。生成函数的高次方我们可以在模 2 21 2^{21} (比序列长度长)意义下进行 DFT \text{DFT} ,然后每一位求出次方后再 DFT \text{DFT} 回来就可以得到答案。

#include<bits/stdc++.h>
#define mkp make_pair
#define pb push_back
#define fi first
#define se second
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int NN=2e6+10,N=5e6+10;
const int mod=998244353,G=3;
int n,K,a[N];
ll ans;

int read()
{
	int ret=0,f=1;char c=getchar();
	while(!isdigit(c)) {if(c=='-')f=0;c=getchar();}
	while(isdigit(c)) ret=ret*10+(c^48),c=getchar();
	return f?ret:-ret;
}

int ipow(int x,int y)
{
	int res=1;
	for(;y;y>>=1,x=(ll)x*x%mod)if(y&1)res=(ll)res*x%mod; 
	return res;
}

namespace NTT
{
	int m,L,rev[N];
	void reget(int sz)
	{
		for(m=1,L=0;m<=sz;m<<=1) ++L;
		for(int i=0;i<m;++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
	}
	void ntt(int *a,int n,int op)
	{
		for(int i=0;i<n;++i) if(i<rev[i]) swap(a[i],a[rev[i]]);
		for(int i=1;i<n;i<<=1)
		{
			int wn=ipow(G,(mod-1)/(i<<1));
			if(op==-1) wn=ipow(wn,mod-2);
			for(int j=0;j<n;j+=(i<<1))
			{
				int w=1;
				for(int k=0;k<i;++k,w=(ll)w*wn%mod)
				{
					int x=a[j+k],y=(ll)w*a[i+j+k]%mod;
					a[j+k]=(x+y)%mod;a[i+j+k]=(x-y+mod)%mod;
				}
			}
		}
		if(op==-1) for(int i=0,inv=ipow(n,mod-2);i<n;++i) a[i]=(ll)a[i]*inv%mod;
	}
}
using namespace NTT;

int main()
{
#ifndef ONLINE_JUDGE
	freopen("G.in","r",stdin);
	freopen("G.out","w",stdout);
#endif
	n=read();K=read();reget(NN);
	for(int i=1;i<=K;++i) a[read()]=1;
	ntt(a,m,1);
	for(int i=0;i<m;++i) a[i]=ipow(a[i],n/2);
	ntt(a,m,-1);
	for(int i=0;i<m;++i) (ans+=(ll)a[i]*a[i])%=mod;
	printf("%lld\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Dream_Lolita/article/details/85339864