NOIP模拟题 2015.8.2 T1
HJWJBSR
posted @ 2015年8月16日 22:28
in 题解
, 356 阅读
题解:考场上面感觉这就是个容斥,于是一直在推式子,一直推到考试结束= =后来讲题才知道这是个DP,设ai,j代表第i轮那个人选数后gcd变成j的概率,然后用j和所有数做一次gcd,然后就可以转移了,但是其中有i个gcd为j的不能转移。然后第二问就可以直接SG搞了,复杂度n^2m
P.S.不知道为毛用SmartC++调试了一下之后代码在sublime里面就不能看了= =
后来手动加空格总算是好了些了
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; #define N 305 #define M 1050 int n,m,sg[N][M],g[M][M],v[N],b[M],st=0;double s[N][M],ans=0; inline int Read() { int x=0;char y; do y=getchar(); while (y<'0'||y>'9'); do x=x*10+y-'0',y=getchar(); while (y>='0'&&y<='9'); return x; } int gcd(int x,int y) { if (g[x][y]) return g[x][y];else return g[x][y]=(y?gcd(y,x%y):x); } void Down(int x,int y) { if (!s[x][y]) return; int w=0,e=0;double q=s[x][y]/(n-x); for (int i=1;i<=n;i++) { e=gcd(y,v[i]); if (e==y) w++;else if (e!=1) s[x+1][e]+=q;else ans+=(x&1)*q; } s[x+1][y]+=q*(w-x); } void Solve(int x,int y) { if (!s[x][y]) return; int k=0;st++; for (int i=1;i<=n;i++) { if (g[y][v[i]]==y) k++;else if (g[y][v[i]]!=1) b[sg[x+1][g[y][v[i]]]]=st; } if (k!=x) b[sg[x+1][y]]=st; for (int i=0;i<=n;i++) if (b[i]!=st) {sg[x][y]=i;return;} } int main() { freopen("game.in","r",stdin);freopen("game.out","w",stdout); n=Read(); for (int i=1;i<=n;i++) v[i]=Read(); s[0][0]=1;Down(0,0); for (int i=1;i<n;i++) for (int j=1;j<=1000;j++) Down(i,j); if (n&1) for (int i=1;i<=1000;i++) ans+=s[n][i]; printf("%.9lf ",ans); for (int i=n;i>0;i--) for (int j=1000;j>=1;j--) Solve(i,j);Solve(0,0); if (sg[0][0]) puts("1.000000000");else puts("0.000000000"); return 0; }