题目
Description
Input
第一行一个正整数n
第二行,n个实数 ,每个实数恰好一位小数,并且这些数字加起来是1
Output
输出一个数,表示答案对 取模。
Sample Input
样例输入1:
2
0.5 0.5
样例输入2:
3
0.3 0.3 0.4
样例输入3:
4
0.2 0.3 0.2 0.3
Sample Output
样例输出1:
1
样例输出2:
804545461
样例输出3:
84928504
Data Constraint
对于10%的数据,n<=1
对于20%的数据,n<=2
对于40%的数据,n<=3
对于60%的数据,n<=4
对于80%的数据,n<=5
对于100%的数据,n<=6
Hint
思路
如果知道表格,那么想求答案只需要简单的DP
设dp[i][j]为走到(i,j)的最大答案
设u=max(dp[1…n][m]),s[i]=u-dp[i][m]。
把所有状态搜出来,状态数量大概有几百
搜出状态后,建立转移关系,高斯消元求解概率即可
代码
#include<bits/stdc++.h>
#define ll long long
#define N 577
#define M 50077
#define mo 1000000007
using namespace std;
int n,bz[M],m,num[N],mul[10],b[10];
ll p[10],a[N][N];
ll power(ll x,ll y)
{
ll s=1;
for(;y;y/=2,x=x*x%mo) if(y&1) s=s*x%mo;
return s;
}
void DFS(int S)
{
for(int i=1; i<=n; i++)
{
int k=0,T=0;
for(int j=1; j<=n; j++) if(S%mul[j]/mul[j-1]==0&&abs(i-j)<=1) k=1;
for(int j=1; j<=n; j++)
{
int mi=n;
if(j>1) mi=min(mi,S%mul[j-1]/mul[j-2]);
mi=min(mi,S%mul[j]/mul[j-1]);
if(j<n) mi=min(mi,S%mul[j+1]/mul[j]);
T+=mul[j-1]*(mi-(i==j)+k);
}
if(!bz[T])
{
bz[T]=++m,num[m]=T,a[m][m]-=1;
a[bz[T]][bz[S]]+=p[i];
DFS(T);
}
else a[bz[T]][bz[S]]+=p[i];
}
}
int main()
{
freopen("one.in","r",stdin);
freopen("one.out","w",stdout);
scanf("%d",&n);
mul[0]=1;
for(int i=1; i<=n+1; i++) mul[i]=mul[i-1]*n;
for(int i=1; i<=n; i++)
{
double k;
scanf("%lf",&k);
p[i]=(ll)(k*10)*power(10,mo-2)%mo;
}
bz[0]=m=1,num[1]=0,a[1][1]=-1;
DFS(0);
for(int i=1; i<=m; i++) a[0][i]=1; a[0][0]=1;
for(int i=0; i<m; i++)
{
if(!a[i][i+1])
{
int j;
for(j=i+1; j<=m; j++) if(a[j][i+1]) break;
for(int k=0; k<=m; k++) swap(a[i][k],a[j][k]);
}
ll inv=power(a[i][i+1],mo-2);
for(int j=0; j<=m; j++) a[i][j]=a[i][j]*inv%mo;
for(int j=0; j<=m; j++) if(j!=i&&a[j][i+1])
{
for(int k=0; k<=m; k++) if(k!=i+1)
a[j][k]=(a[j][k]-a[i][k]*a[j][i+1])%mo;
a[j][i+1]=0;
}
}
ll ans=0;
for(int i=1; i<=m; i++)
{
int S=num[i];
memset(b,0,sizeof(b));
for(int j=1; j<=n; j++) if(S%mul[j]/mul[j-1]==0)
b[j-1]=b[j]=b[j+1]=1;
ll s=1;
for(int j=1; j<=n; j++) if(!b[j]) s-=p[j];
ans+=a[i-1][0]*s%mo;
}
printf("%lld",(ans%mo+mo)%mo);
}