1. 程式人生 > >[luogu4459][BJOI2018]雙人猜數遊戲(DP)

[luogu4459][BJOI2018]雙人猜數遊戲(DP)

clas nbsp 其余 def 同時 can target size math

https://zhaotiensn.blog.luogu.org/solution-p4459

從上面的題解中可以找到樣例解釋,並了解兩個人的思維方式。

A和B能從“不知道”到“知道”的唯一情況,就是根據已知條件(也就是已經說的”不知道“次數)排除手上數的所有其它合法拆分方案。

那麽,設dp[i][j][k]表示,兩個數分別為i,j,當前已經說了k次不知道,這個數是否能確定(也就是某方知道了答案)。

那麽有兩種轉移

dp[i][j][k]|=dp[i][j][k-2] 一輪之前就已經知道了這輪肯定也知道。

對於B: dp[i-s][j+s][k-1]在s取遍所有合法取值時,只有s=0是false,其余全為true。也就是i+j的所有其它合法拆分方案在說了k-2次不知道後,A都應該說知道答案了,唯獨這種方案仍不知道,那麽B就肯定可以確定這個數了。

對於A: 同理,將i*j拆分即可。

考慮什麽情況下滿足題設條件,即說了t次”不知道“後雙方都知道答案了。

那麽就是dp[i][j][t-1]為false而dp[i][j][t]為true。但是這樣只能保證已經有一方已知答案,同時還要保證的是另一方當這方說”知道了“之後也知道了答案,而說之前還不知道,這需要另一個類似的暴力拆分解決。

所以我們分別模擬兩人的思維,後期每個點大約跑幾分鐘。

 1 #include<cmath>
 2 #include<cstdio>
 3 #include<algorithm>
 4
#define rep(i,l,r) for (int i=(l); i<=(r); i++) 5 using namespace std; 6 7 const int N=2010; 8 int s,t; 9 bool flag,f[N][N][20]; 10 char a[10]; 11 12 bool chk1(int x,int y,int t){ 13 int num=x*y,len=sqrt(x*y),x1=0,y1=0,cnt=0; 14 rep(i,s,len) 15 if(num%i==0 && ((!f[i][num/i][t-1
])||(!t))) 16 x1=i,y1=num/i,cnt++; 17 if(cnt==1 && x1==x && y1==y) return 1; else return 0; 18 } 19 20 bool chk2(int x,int y,int t){ 21 int num=x+y,len=(x+y)/2,x1=0,y1=0,cnt=0; 22 rep(i,s,len) 23 if((!f[i][num-i][t-1])||(!t)) 24 x1=i,y1=num-i,cnt++; 25 if(cnt==1 && x1==x && y1==y) return 1; else return 0; 26 } 27 28 bool chk3(int x,int y,int t){ 29 int num=x*y,len=sqrt(x*y),x1=0,y1=0,cnt=0; 30 rep(i,s,len) 31 if(num%i==0 && (f[i][num/i][t]&&(t<2||(!f[i][num/i][t-2])))) 32 x1=i,y1=num/i,++cnt; 33 if(cnt==1 && x1==x && y1==y) return 1; else return 0; 34 } 35 36 bool chk4(int x,int y,int t){ 37 int num=x+y,len=(x+y)/2,x1=0,y1=0,cnt=0; 38 rep(i,s,len) 39 if(f[i][num-i][t]&&(t<2||(!f[i][num-i][t-2]))) 40 x1=i,y1=num-i,++cnt; 41 if(cnt==1 && x1==x && y1==y) return 1; else return 0; 42 } 43 44 int main(){ 45 freopen("guess.in","r",stdin); 46 freopen("guess.out","w",stdout); 47 scanf("%d",&s); scanf("%s",a+1); scanf("%d",&t); 48 if (a[1]==A) flag=0; else flag=1; 49 rep(i,0,t){ 50 flag^=1; 51 rep(j,s,1000) rep(k,s,1000){ 52 if(i>=2)f[j][k][i]=f[j][k][i-2]; 53 f[j][k][i]|=flag?chk1(j,k,i):chk2(j,k,i); 54 } 55 } 56 int sum=2*s,x=0,y=0; 57 while (1){ 58 rep(i,s,sum/2){ 59 x=i; y=sum-i; flag=f[x][y][t]; 60 if (!flag) continue; 61 rep(j,0,t-1) if(f[x][y][j]){ flag=false; break; } 62 if (!flag) continue; 63 if(((t&1)&&a[1]==A)||((!(t&1))&&a[1]==B)) flag=chk3(x,y,t); else flag=chk4(x,y,t); 64 if (!flag) continue; 65 printf("%d %d\n",x,y); return 0; 66 } 67 sum++; 68 } 69 return 0; 70 }

[luogu4459][BJOI2018]雙人猜數遊戲(DP)