bzoj3191卡牌游戏

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3191

原本想模拟过程,从t个人推到1个人;

  但是怎么转移呢?想状压,可是50位压不到角标里。

  那就随便转移吧,把当前人的生存方案数加给所有有可能成为下一轮中自己的人。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=55;
int n,m,a[N];
ll dp[N][N],sum;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    dp[n][1]=1;
    for(int t=n;t>1;t--)
        for(int i=1;i<=n;i++)
            if(dp[t][i])
            {
//                printf("t=%d i=%d dp=%d\n",t,i,dp[t][i]);
                for(int j=1;j<=m;j++)
                {
                    int c=a[j]%t,l=i+c+1,r=i-(t-c-1);
//                    printf("i=%d aj=%d l=%d r=%d\n",i,a[j],l,r);
                    if(l>r)for(int k=1;k<=n;k++)if(k>=r||k<=l)dp[t-1][k]+=dp[t][i];
                    else for(int k=l;k<=r;k++)
                        dp[t-1][k]+=dp[t][i];
                }
            }
    for(int i=1;i<=n;i++)sum+=dp[1][i];
    for(int i=1;i<=n;i++)
        printf("%.2lf",(double)dp[1][i]*100/(double)sum),cout<<"% ";
    return 0;
}
View Code

这当然是不对的。那个“有可能成为下一轮中自己的人”不能保证就是下一轮中的自己。

那怎么办?看看TJ,发现大家是用相对编号来记录下一轮中的自己是哪个人的。

  用记忆化搜索可以想得更灵活一点。以后尝试用这个角度思考。不然自己容易想不出来……

概率不用每一步都算好。可以之前一直算的是方案数,最后再换算成概率。有时候这样比较方便。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=55;
int n,m,a[N];
bool vis[N][N];
double dp[N][N],sum;
double sol(int i,int j)
{
    if(vis[i][j])return dp[i][j];vis[i][j]=1;
    if(i==1)return dp[i][j]=1;
    for(int k=1;k<=m;k++)
        if(a[k]%i!=j%i)//j%i,不是j (j==i)
            dp[i][j]+=sol(i-1,(j-(a[k]%i)+i)%i);
//    dp[i][j]/=m;
    return dp[i][j];
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)sum+=sol(n,i);
    for(int i=1;i<=n;i++)
    {
        printf("%.2lf%%",sol(n,i)/sum*100);
        if(i!=n)printf(" ");
    }
    return 0;
}

 

posted on 2018-06-04 11:57  Narh  阅读(125)  评论(0编辑  收藏  举报

导航