https://www.codechef.com/problems/SEAGM

題意:

n個數(可能存在相同的數),雙方輪流取數。如果在一方選取之後,所有
已選取數字的GCD變為1,則此方輸。
問:
1 若雙方均採取最優策略,先手是否必勝?
2 若雙方隨機取數,先手獲勝的概率為多少?
$n,ai \le 100$


狀態比較難想,核心是找到一個劃分階段的順序:根據$GCD$劃分階段

$GCD$是隻會減小不會增加的

課件上的狀態是$f[i][j]$表示當前$GCD$為$i$,沒選的$i$的倍數有$j$個,感覺有點奇怪...

看了一下官方題解,意識到只要記錄$j$為當前已經選的有$j$個就好了,已經選的一定是$i$的倍數,這樣就和其他的狀態比較像了

轉移還是比較好想的

$1.\ f[i][j] \rightarrow f[i][j+1]\ :\ j<mult[i]$

$2.\ f[i][j] \rightarrow f[gcd(i,k)][j+1]\ :\ 1 \le gcd(i,k) \le i$

記憶化搜尋倒推就行了

PS:給$gcd$加上記憶化之後$0s$就跑過去了....

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=;
const double eps=1e-;
inline int read(){
char c=getchar();int x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
int n,a[N];
int g[N][N];
int gcd(int a,int b){return g[a][b] ? g[a][b] : g[a][b]=(b==?a:gcd(b,a%b));}
//int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int f[N][N];
double p[N][N];
bool dfsWin(int u,int c){//printf("dfsWin %d %d\n",u,c);
int &re=f[u][c];
if(c==n) re=;//has chosen all
if(u==) re=;//win
if(re!=-) return re; re=;
int mult=;
for(int i=;i<=n;i++) if(gcd(u,a[i])==u) mult++;
if(c<mult&&!dfsWin(u,c+)) re=;
else{
for(int i=;i<=n;i++)
if(gcd(u,a[i])>&&gcd(u,a[i])!=u)
if(!dfsWin(gcd(u,a[i]),c+)) {re=;break;}
}
return re;
}
double dfsPro(int u,int c){//printf("dfsPro %d %d\n",u,c);
double &re=p[u][c];
if(c==n) re=0.0;
if(u==) re=1.0;
if(re>-0.9) return re; re=0.0;
int mult=;
for(int i=;i<=n;i++) if(gcd(u,a[i])==u) mult++;
if(c<mult) re+= (double)(mult-c) / (n-c) * (-dfsPro(u,c+));
for(int i=;i<=n;i++)
if(gcd(u,a[i])>&&gcd(u,a[i])!=u)
re+=(double) / (n-c) *(-dfsPro(gcd(u,a[i]),c+));
if(abs(re)<eps) re=;
return re;
}
int main(){
freopen("in","r",stdin);
int T=read();
while(T--){
n=read(); int g=;
for(int i=;i<=n;i++) a[i]=read(),g=gcd(a[i],g);
if(g>){printf("%d %.4lf\n",n&,double(n&));continue;} for(int i=;i<N;i++) for(int j=;j<N;j++) f[i][j]=-,p[i][j]=-1.0;
int flag=dfsWin(,);
printf("%d ",flag); double prob=dfsPro(,);
printf("%.4lf\n",prob);
}
}