1. 程式人生 > 其它 >[COCI2021-2022#1] Kamenčići

[COCI2021-2022#1] Kamenčići

[COCI2021-2022#1] Kamenčići

題目連結:[P7928 COCI2021-2022#1] Kamenčići - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)


​ 容易想到一個狀態 \(dp_{l,r,a,b,0/1}\) 表示還剩 \(l,r\) 這個區間沒拿, Alice 拿了 \(a\) 塊紅石頭,Bob 拿了 \(b\) 塊紅石頭,且當前是 Alice/Bob 選擇拿石頭,最後的勝者是誰。那麼轉移就是暴力轉移。

\[dp_{l,r,a,b,0}=dp_{l+1,r,a,b+(s[l]=='C'),1}==1 \&\& dp_{l,r-1,a,b+(s[r]=='C'),1}==1 \]

​ 類似的,我們可以寫出 \(opt=1\)

時的轉移式。

​ 注意到,由於總共的紅石頭數不變,一個區間內紅石頭數也不變,所以我們只要知道其中一個人拿了幾塊石頭就可以用字首和算出另外一個人拿了幾塊石頭。

​ 那麼就優化了一維,時空複雜度為 \(O(n^3)\)

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 355;
bool Small;
int n,K,suml[MAXN],sumr[MAXN];
int dp[MAXN][MAXN][MAXN][2];
char s[MAXN];
bool Sunny;
int dfs(int l,int r,int k,int opt)
{
	if(suml[l-1]+sumr[r+1]-k==K) return opt;
	if(dp[l][r][k][opt]!=-1) return dp[l][r][k][opt];
	int tmp1,tmp2;
	tmp1=dfs(l+1,r,suml[l-1]+sumr[r+1]-k,opt^1);
	tmp2=dfs(l,r-1,suml[l-1]+sumr[r+1]-k,opt^1);
	int ans;
	if(opt) ans=(tmp1==1||tmp2==1);
	else ans=(tmp1==1&&tmp2==1);
	return dp[l][r][k][opt]=ans;
}
int main()
{
	memset(dp,-1,sizeof dp);
	scanf("%d %d",&n,&K);
	scanf("%s",s+1);
	for(int i=1;i<=n;++i)
		suml[i]=suml[i-1]+(s[i]=='C');
	for(int i=n;i>=1;--i)
		sumr[i]=sumr[i+1]+(s[i]=='C');
	if(dfs(1,n,0,1)) printf("DA\n");
	else printf("NE\n");
	return 0;
}
路漫漫其修遠兮,吾將上下而求索。