ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2019-02-16 13:53:26  阅读:328  来源: 互联网

标签:BJOI2018 include 猜数 sum flag dp 拆分 luogu4459 知道


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有