Codeforces Global Round 12

C.Errich-Tac-Toe

題目描述ios

 

解法c++

先考慮 \(\tt easy\space version\),針對 \(\lfloor\frac{k}{3}\rfloor\) 來構造,能夠把整張圖三染色,必定有一種顏色知足格子 X 的數量不超過 \(\lfloor\frac{k}{3}\rfloor\),把這種顏色的X所有改爲O便可。ide

對於 \(\tt hard\space version\),仍是沿用染色的思路,咱們讓任意相鄰的三個格子出現XO,也就是把某種顏色所有改爲X,某種顏色所有改爲O,那麼咱們讓出現次數最多的顏色不變,這樣剩下不超過 \(\frac{2k}{3}\) 的格子,XOOX必定有一種能讓改變的格子不超過 \(\frac{1}{2}\)(由於XXOO的貢獻是 \(1\);XOOX對某一個貢獻是 \(2\),對另外一個沒有貢獻),因此改變的總格子數不超過 \(\lfloor\frac{k}{3}\rfloor\)spa

實現的時候討論每種修改方案,看哪一種知足條件便可。code

總結get

限制出如今相鄰格子上,染色是很好的解決方案。string

#include <cstdio>
#include <iostream>
using namespace std;
const int M = 305;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n;char a[M][M],b[M][M];
int check(string s)
{
	int c1=0,c2=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
		{
			b[i][j]=a[i][j];
			if(a[i][j]!='.' && s[(i+j)%3]!='.')
				b[i][j]=s[(i+j)%3];
		}
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if(a[i][j]!='.')
				c1++,c2+=(a[i][j]!=b[i][j]);
	return c2<=c1/3;
}
void print()
{
	for(int i=1;i<=n;i++,puts(""))
		for(int j=1;j<=n;j++)
			printf("%c",b[i][j]);
}
void work()
{
	n=read();
	for(int i=1;i<=n;i++)
		scanf("%s",a[i]+1);
	if(check(".XO")) print();
	else if(check(".OX")) print();
	else if(check("X.O")) print();
	else if(check("O.X")) print();
	else if(check("OX.")) print();
	else if(check("XO.")) print();
}
signed main()
{
	T=read();
	while(T--) work();
}

H.Multithreading

題目描述it

點此看題io

解法class

首先考慮沒有問號的狀況怎麼計算答案,設 \(b_o,b_e\) 分別表示奇數位置和偶數位置上 \(b\) 顏色的個數,\(w_o,w_e\) 相似,其實貪心均可以猜出結論:\(f(c)=\frac{1}{2}|b_o-b_e|\),設 \(|b_o-b_e|=2k\),證實:

  • 首先證實 \(f(c)\leq k\),能夠經過構造一組有 \(k\) 個異色交點的解來完成,咱們先把相鄰兩個位置奇偶性不一樣的同色點鏈接起來,這時候必定不會產生異色交點。剩下的點知足 \(b_o=2k,w_e=2k\),那麼咱們按照 \(bwbw...bwbw\) 這樣相鄰的同色點鏈接,發現會產生 \(k\) 個交點。
  • 而後證實 \(f(c)\geq k\),咱們聲明最優解中不存在同色交點,由於若是存在能夠經過調整使之不交,而且異色交點個數不增。因此就能夠假設不存在同色交點,由於 \(|b_o-b_e|=2k\),因此必然會有 \(k\) 條鏈接奇偶性相同位置的邊,而且這些邊會把原圖分紅兩部分知足點數都爲奇數,那麼必然存在交點,因爲不是同色交點,那麼必定是異色交點,因此 \(f(c)\geq k\)

這個結論能夠用於計數,設 \(F\) 爲?的個數,\(F_o\) 爲偶數位置?的個數,咱們枚舉?中有 \(i\) 個位置,若是是偶數位置染色爲 \(b\),不然染色成 \(w\),其餘位置用相反的方法染色。設 \(i\) 中染色 \(b\) 的個數爲 \(a\),那麼 \(b\) 顏色在偶數位置的個數是 \(b_e+a\),在奇數位置的個數是 \(b_o+F_o-i+a\)(由於 \(i-a\) 是奇數位置用掉的?個數),因此:

 

\[f(c)=\frac{1}{2}|b_e+a-(b_o+F_o-i+a)|=\frac{1}{2}|b_e-b_o-F_o+i| \]

 

設 \(x=b_o+F_o-b_e=\frac{n}{2}-w_o-b_e\),因此 \(f(c)=\frac{1}{2}|x-i|\),\(i\) 對應的方案數有 \({F\choose i}\) 種,因此答案是:

 

\[\frac{1}{2^F}\sum_{0\leq i\leq F\\i=x\bmod2}|x-i|\cdot {F\choose i} \]

 


從 \(\tt easy\space version\) 繼續,暫且忽略 \(\frac{1}{2^F}\) 這個係數,咱們把絕對值拆掉(默認 \(i=x\bmod 2\)):

 

\[\sum_{0\leq i\leq x} x{F\choose i}-\sum_{0\leq i\leq x} i{F\choose i}+\sum_{x\leq i\leq F}i{F\choose i}-\sum_{x\leq i\leq F}x{F\choose i} \]

 

首先咱們把組合數前面的係數拿掉,對於 \(x{F\choose i}\) 直接提到前面去,\(i{F\choose i}=F{F-1\choose i-1}\),把 \(F\) 拿到前面去。

還要解決 \(i=x\bmod 2\) 的問題,由於 \({F\choose i}={F-1\choose i}+{F-1\choose i-1}\) 能夠直接轉成前綴和的形式,組合數前綴和是很容易修改的,只須要使用這個恆等式:

 

\[\sum_{i=0}^k{F+1\choose i}=2\sum_{i=0}^k{F\choose i}-{F\choose k} \]

 

總結

通常這種題都有結論來支持計數,要大膽猜結論。

推式子的時候注意絕對值能夠拆掉,若是式子的主體是組合數,能夠嘗試把他變成組合數前綴和的形式。

#include <cstdio>
const int M = 200005;
const int MOD = 998244353;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,x,F,ans,inv[M],fac[M];char s[M];
int Abs(int x)
{
	return x>0?x:-x;
}
void init()
{
	inv[0]=inv[1]=fac[0]=1;
	for(int i=2;i<=n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=1;i<=n;i++) inv[i]=inv[i-1]*inv[i]%MOD;
	for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%MOD;
}
int C(int n,int m)
{
	return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
signed main()
{
	n=read();m=read();
	init();
	scanf("%s",s+1);
	x=n/2;
	for(int i=1;i<=n;i++)
	{
		F+=(s[i]=='?');
		if(i%2 && s[i]=='w') x--;
		if(i%2==0 && s[i]=='b') x--;
	}
	for(int i=0;i<=F;i++)
		if(i%2==(x%2+2)%2)
			ans=(ans+Abs(x-i)*C(F,i))%MOD;
	for(int i=1;i<=F;i++)
		ans=ans*inv[2]%MOD;
	printf("%lld\n",ans);
}
相關文章
相關標籤/搜索