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

AA

簽到題

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;
}

BB

這麼簡單比賽的時候竟沒想出來

簡明題意:

給定一個01串tt,求有個子序列正好爲tt的01串ss,同時滿足ss的最小正週期最小.

顯然,所有數都相同時輸出讀入的即可.

否則,可以用nn個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;
}

CC

找循環節即可.

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;
}

DD

貪心.

從後往前選更容易判斷是否合法.
我們貪心維護一個|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;
}

EE

容斥原理(或者是第二類斯特林數(還沒學,之後要補))

題意:

nnnn*n的棋盤上有n個車,已知kk,要使得每個格子都能被車攻擊且車之間兩兩能攻擊的情況正好爲kk個.(中間不能有其他的車)求總方案個數.

顯然,車要麼排滿行,要麼排滿列.

這兩種情況顯然是可以一一對應的,所以我們僅求一個即可.

考慮每一列都排滿,那麼有車的行顯然有nkn-k個.

開始容斥:

q=nkq=n-k.

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

意思:qq行任選爲qnq^n,顯然這樣有空行,所以要-Cqq1(q1)nC_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;
}

FF

狀壓DP.

單組數據複雜度O(n3n)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降智了?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章