其他分享
首页 > 其他分享> > [luogu4459][BJOI2018]双人猜数游戏(DP)

[luogu4459][BJOI2018]双人猜数游戏(DP)

作者:互联网

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 }

 

标签:BJOI2018,include,猜数,sum,flag,dp,拆分,luogu4459,知道
来源: https://www.cnblogs.com/HocRiser/p/10387473.html