原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=6266
以及pdf :http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf
题意:给出 N 堆石头,每堆对应有 ai 个。其中A取时 取两次,B取时取一次(每次取时至少取一个,最多取完一堆)现在给出堆数以及对应的每堆个数,以及先后手关系(输入1代表A先手,输入2代表B先手)。问最后先手是否能取得胜利。
思路:对于博弈问题,一般能找规律的找规律,不行就用sg函数。(...本弱鸡不会用sg函数写这个题)
所以我们可以先对所有简单情况进行列举。同时,对于博弈问题,我们一定是要着重观察 先手对应的 P-position.即后手必胜,(或者说对于当前取的人必输的状态)。因为 P态只能转到N态 ,而 N至少有一种可能转到P 状态。所以只要找到 P 状态,则其他所有状态均为 先手获胜。
对于石子问题,我们从最简单能判断的状态举例起:由于 全部为 1时取法是固定的 所以先观察全为1的状态:
A先手: 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 ... A赢 A赢 A输 A赢 A赢 所以全为1时,我们可以看到只要是 3 的倍数 A必输,即A处于P-position
当不全为1时(X,Y,Z为任意数)
X X Y 1 X Y 1 1 X Y ... 由此递推下去发现A不会再输了
A赢 A赢 A赢(转换成1 1 1) A赢 B先手: 1 1 1 1 1 1 1 1 1 1 ... A输 A赢 A赢 A输 所以当全为1时,我们发现 只要是 n%3==1 则B能赢,否则会输
当不全为1时(X,Y,Z为任意数)
X X Y 1 1 X 1 1 X Y 1 1 1 X 1 1 1 1 X ...
A输 A输 A输 A赢 A输(从1 1 X递推过来) A赢
综上就会发现
(1)A先手:当 全为 1 且个数 %3==0,则A输
(2)B先手:当 1 的个数大于等于 n-1 时,且 n%3 == 1 A输,如果 1 的个数 为 n-1 且 n%3==0 时A输
code:
#include <algorithm> #include <iostream> #include <cstdio> #include <cstring> #include <string> #include <cmath> #define IOS ios::sync_with_stdio(0); cin.tie(0); #define mp make_pair using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const double Pi = acos(-1.0); const double esp = 1e-9; const int inf = 0x3f3f3f3f; const int maxn = 1e3+7; const int maxm = 1e6+7; const int mod = 1e9+7; int main(){ int T; cin>>T; while(T--){ int n,m,tmp; int cnt = 0; cin>>n>>m; for(int i=0;i<n;i++){ scanf("%d",&tmp); if(tmp==1) cnt++; } //当所有全为1,切n%3时 if(m==1){ if(cnt==n&&!(n%3)) cout<<"No"<<endl; else cout<<"Yes"<<endl; }else{ if((cnt>=n-1&&(n%3)==1)||(cnt==n-1&&!(n%3))) cout<<"No"<<endl; else cout<<"Yes"<<endl; } } }