ARC109E 1D Reversi Builder


一排格子,每個格子黑白顏色\(c_i\)。一開始從某個位置\(s\)開始,\(s\)上放顏色\(c_i\)的棋子。每次選擇一個和有棋子格子相鄰的空格子\(x\),放顏色為\(c_x\)的棋子,並找到離\(x\)最近的顏色同為\(c_x\)棋子\(y\),將\(x,y\)之間的棋子都反色。如果找不到就算了。

(其實就是黑白棋)

兩人博弈,先手最大化黑子個數。

對於所有的\(s\),分別求:對所有的染色方案\(\{c_i\}\)求最終黑子個數的和(期望)。

\(n\le 2*10^5\)


發現了性質之后它似乎就變成一道簡單題了……

雖然我是打表發現的。

可以發現無論怎樣操作,中間的連通塊不可能出現黑白黑的情況。可以歸納。

根據以上結論,進一步發現,如果兩端同色,最終所有棋子一定同色;如果兩端異色,先手希望盡量往黑色那邊走,后手希望盡量往白色那邊走,誰先走到,中間一大塊(即:除去兩端的同色段)就是誰的。

根據這個性質計算即可。

有個比較陽間的算法:首先算兩端同色。對於兩端異色,設左端連續段為\([1,L]\),右端連續段為\([R,n]\),當\(s-L\neq R-s\)時,一種狀態和它完全取反的狀態的答案是互補的。所以只需要特別計算\(s-L=R-s\)的情況多加一次即可。


using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
#define N 200005
#define ll long long 
#define mo 998244353
ll qpow(ll x,ll y=mo-2){
	ll r=1;
	for (;y;y>>=1,x=x*x%mo)
		if (y&1)
			r=r*x%mo;
	return r;
}
int n;
ll pw2[N*2],f[N];
ll ans[N];
void calc(int n){
	pw2[0]=1;
	for (int i=1;i<=n*2;++i)
		pw2[i]=pw2[i-1]*2%mo;
	ll sum=0;
	(sum+=pw2[n-2]*n)%=mo;
	(sum+=pw2[n-2]*n)%=mo;
	for (int i=1;i<=n;++i)
		ans[i]=sum;
//	for (int i=1;i<=n;++i)
//		for (int L=1;L<=n;++L){
//			int R=i*2-L;
//			if (R>=L+3 && R<=n)
//				(ans[i]+=(R-L-1)*pw2[R-L-3])%=mo;
//		}
//	for (int i=1;i<=n;++i)
//		for (int t=2;t<=i-max(2*i-n,1);++t)
//			(ans[i]+=(2*t-1)*pw2[2*t-3])%=mo;
	for (int i=2;i<=n;++i)
		f[i]=(f[i-1]+(2*i-1)*pw2[2*i-3])%mo;
	for (int i=3;i<=n-2;++i){
//		assert(i-max(2*i-n,1)>=0);
		(ans[i]+=f[i-max(2*i-n,1)]-f[2-1]+mo)%=mo;
	}
	ll inv=qpow(pw2[n]);
	for (int i=1;i<=n;++i)
		ans[i]=ans[i]*inv%mo;
}
int main(){
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
	scanf("%d",&n);
	if (n==1){
		printf("%d\n",qpow(2));
		return 0;
	}
	calc(n);
	for (int i=1;i<=n;++i)
		printf("%lld\n",ans[i]);
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM