Educational Codeforces Round 86 [Rated for Div. 2] Solution

A A

签到题

int T;
ll x,y,a,b; 

int main() {
	qr(T);while(T--) {
		qr(x); qr(y); qr(a); qr(b);
		if(x>y) swap(x,y);
		if(a*2>b) pr2(b*x+(y-x)*a);
		else pr2((x+y)*a);
	}
	return 0;
}

B B

这么简单比赛的时候竟没想出来

简明题意:

给定一个01串 t t ,求有个子序列正好为 t t 的01串 s s ,同时满足 s s 的最小正周期最小.

显然,所有数都相同时输出读入的即可.

否则,可以用 n n 个01来输出.(显然一定满足条件)

int T,n;
char s[N];

int main() {
	qr(T); while(T--) {
		scanf("%s",s+1); n=strlen(s+1);
		bool same=1;
		for(int i=2;s[i];i++) if(s[i]!=s[1]) {same=0;break;}
		if(same) puts(s+1);
		else {for(int i=1;i<=2*n;i++) putchar((i&1)+'0'); puts("");}
	}
	return 0;
}

C C

找循环节即可.

int T,a,b,q,s[N],n;

ll f(ll x) {return 1LL*(x/n)*s[n]+s[x%n];}

int main() {
	qr(T); while(T--) {
		qr(a); qr(b); qr(q);
		n=a*b;
		for(int i=1;i<=n;i++) s[i]=((i%a)%b!=(i%b)%a)+s[i-1];
		while(q--) {
			ll l,r; qr(l); qr(r);
			pr1(f(r)-f(l-1));
		}
		puts("");
	}
	return 0;
}

D D

贪心.

从后往前选更容易判断是否合法.
我们贪心维护一个|testdata|不严格下降序列,在不得不扩容时扩容即可.

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct edge{int y,next;}e[N<<1]; int len,last[N],cnt[N];
void ins(int x,int y) {e[++len]=(edge){y,last[x]};last[x]=len;cnt[x]++;}
int n,m,a[N],c[N],t,ans;

int main() {
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&t),a[t]++;
	for(int i=1;i<=m;i++) scanf("%d",&c[i]);
	for(int i=m; i;i--) {//存储大小满足不严格下降 
		n=0;
		for(int j=(1<<17);j>=1;j/=2)
			if(cnt[n+j]==c[i]) n+=j;
		for(int j=a[i];j--; ins(n,i))
			while(cnt[n]==c[i]) n++;
		ans=max(ans,n);
	}
	printf("%d\n",ans+1);
	for(int i=0;i<=ans;i++) {
		printf("%d",cnt[i]);
		for(int k=last[i];k;k=e[k].next)
			printf(" %d",e[k].y);
		puts("");
	}
	return 0;
}

E E

容斥原理(或者是第二类斯特林数(还没学,之后要补))
或者二项式反演直接套(本质也是容斥)

题意:

n n n n*n的棋盘上有n个车 ,已知 k k ,要使得每个格子都能被车攻击且车之间两两能攻击的情况正好为 k k 个.(中间不能有其他的车)求总方案个数.

显然,车要么排满行,要么排满列.

这两种情况显然是可以一一对应的,所以我们仅求一个即可.

考虑每一列都排满,那么有车的行显然有 n k n-k 个.

开始容斥:

q = n k q=n-k .

a n s = i = 1 q ( 1 ) q i C q q i i n ans=\sum_{i=1}^q (-1)^{q-i} * C_q^{q-i} * i^n

意思: q q 行任选为 q n q^n ,显然这样有空行,所以要- C q q 1 ( q 1 ) n C_q^{q-1}*(q-1)^n

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=2e5+20,mod=998244353;

ll n,m,q,jc[N],inv[N],ans,f;

ll power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=c*a%mod;
		a=a*a%mod; b=b>>1;
	}
	return c;
}

ll C(ll x,ll y){return jc[x]*inv[y]%mod*inv[x-y]%mod;}

int main() {
	scanf("%lld%lld",&n,&m);
	if(m>=n) puts("0");
	else {
		jc[0]=1;for(int i=1;i<=n;i++) jc[i]=jc[i-1]*i%mod;
		if(!m) return printf("%lld\n",jc[n]),0;
		inv[n]=power(jc[n]);for(int i=n;i;i--) inv[i-1]=inv[i]*i%mod;
		f=1;q=n-m;
		for(int i=q;i>0;i--) {
			ans+=f*power(i,n)*C(q,q-i)%mod;
			f=-f;
		}
		ans=(ans%mod+mod)%mod;
		printf("%lld\n",ans*2*C(n,m)%mod);
	}
	return 0;
}

F F

状压DP.

单组数据复杂度 O ( n 3 n ) O(n*3^n) .

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=18,M=1<<15|10;

struct node {
	int x,y,tx,ty;
	//操作数,末尾数,转移函数
	node(int x=M,int y=0,int tx=0,int ty=0):x(x),y(y),tx(tx),ty(ty){};
	bool operator <(node b) const {
		return x!=b.x?x<b.x:y<b.y;
	}
	node get(int a,int b,int c,int d) {
		return {x+a,b,c,d};
	}
}f[N][M],ans[N];

int T,n,m,a[N],sum[M],cnt[M],lg[M],tot;

int main() {
	scanf("%d",&T);
	for(int i=1;i<M;i++) cnt[i]=cnt[i&(i-1)]+1;
	for(int i=0;i<15;i++) lg[1<<i]=i;
	while(T--) {
		scanf("%d",&n);m=1<<n;
		for(int i=0;i<n;i++) scanf("%d",&a[i]);
		for(int i=1;i<m;i++) sum[i]=sum[i&(i-1)]+a[lg[i&(-i)]];
		for(int i=0;i<=n;i++) for(int j=0;j<m;j++) f[i][j]=node();
		f[0][m-1]=node(0);
		for(int i=1;i<=n;i++)
			for(int j=0;j<m;j++) if(f[i-1][j].x^M) {//上一个状态 
				f[i][j]=min(f[i][j],f[i-1][j]);
				if(j>>(i-1)&1) {
					int mask=j^(1<<(i-1));
					for(int s=mask;  ;s=(s-1)&mask) {
						int t=s|(1<<(i-1));//当前选择 
						if(f[i-1][j].y<sum[t])//上升 
							f[i][j^t]=min(f[i][j^t],f[i-1][j].get(cnt[s],sum[t],i-1,j));
						if(!s) break;
					}
				}
			}
		printf("%d\n",f[n][0].x); tot=0;
		for(int i=n,j=0;j^(m-1);	) {
			int x=f[i][j].tx,y=f[i][j].ty,t=j^y^(1<<x);
			for(int k=0;k<n;k++) if(t>>k&1) ans[++tot]=node(k,x);
			i=x; j=y;
		}
		for(int i=1;i<=tot;i++) {
			int x=ans[i].x,y=ans[i].y;
			printf("%d %d\n",x+1,y+1);
			for(int k=i+1;k<=tot;k++) 
				ans[k].x-=(ans[k].x>x),
				ans[k].y-=(ans[k].y>x);
		}
	}
	return  0;
}

后记

考场上只做了2T,难道是打完ABC降智了?

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/105790810