NOIP模拟题 2015.8.2 T1
HJWJBSR
posted @ 2015年8月16日 22:28
in 题解
, 396 阅读
题解:考场上面感觉这就是个容斥,于是一直在推式子,一直推到考试结束= =后来讲题才知道这是个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;
}
评论 (0)