Chieh's Blog

Because Of Coding

ZOJ Problem Set - 3777 Problem Arrangement

Chieh posted @ 2015年7月23日 15:04 in ZOJ , 369 阅读

飞机票:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5264

题意:给你n个题目,每个题目放在第i个位置有个值,有个程序可以随机生成1~n的排列,求生成的排列值大于m的期望次数

分析:这里的话需要推一下公式,需要用到极限的定理,因为假设n!种方案里,可行的方案概率为p,不可行为q(即1-p),则期望次数为

limn->无穷p*q^0*1+p*q^1*2+p*q^2*3....+p*q^(n-1)*n这个极限怎么求是关键,这里可以用错位相减法,即将式子乘以q,则为

qlimn->无穷                p*q^1*1+p*q^2*2....+p*q^(n-1)*(n-1)+p*q^(n)*n,然后两式一减,为(1-q)limn->无穷p+p*q^1+p*q^2...p*q^(n-1)-p*q^n*n,等比求和,即limn->无穷p*(1-q^n)/(1-q)-p*q^(n)*n,求极限后为可知这个极限为1/(1-q)即1/p,所以期望的次数是1/p,现在要求的是满足大于等于m的排列有多少个,因为n最大只有12,所以可以用状态压缩,最大也就只有4095,具体怎么搞?假设当前要确定的是第i个位置的数字,然后假设第j个题目放在第i个位置,那么我们可以去找i-1个位置,因为i-1个位置可以用二进制表示,所以可以很快找到然后把i-1个位置里面的值加上j在第i个的值,最后的话,大于等于m的方案数就是我们要求的复杂度O(n*n*2^n),最后啪啪啪就可以AC了

/*
Author:Chieh
Because Of Coding
*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#define LL long long
#define INF 1e9
#define EPS 1e-9
using namespace std;
const int maxn=13;
int C[maxn];
int ai[maxn][maxn];
int bi[5000][567];
int n,m,T;
void init()
{
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++)
        for(int j=1; j<=n; j++)scanf("%d",&ai[i][j]);
}
int gcd(int a,int b)
{
    if(a<b)swap(a,b);
    if(a%b==0)return b;
    return gcd(b,a%b);
}
void play()
{
    memset(bi,0,sizeof(bi));
    bi[0][0]=1;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=n; j++)
        {
            for(int k=1; k<C[n]; k++)
            {
                int t=k;
                bool flag=1;
                int q=0;
                for(int l=n-1; l>=0; l--)
                {
                    if(l+1==j&&t-C[l]<0)
                    {
                        flag=0;
                        break;
                    }
                    if(t-C[l]>=0)
                    {
                        t-=C[l];
                        q++;
                    }
                }
                if(q!=i)flag=0;
                if(flag)
                {
                    for(int l=0; l<=500; l++)
                    {
                        int now=l+ai[j][i];
                        if(now>500)now=500;
                        bi[k][now]+=bi[k-C[j-1]][l];
                    }
                }
            }.
        }
    }
    int fz=0;
    int fm=1;
    for(int i=m; i<=500; i++)fz+=bi[C[n]-1][i];
    for(int i=1; i<=n; i++)fm*=i;
    if(fz==0)printf("No solution\n");
    else
    {
        int p=gcd(fz,fm);
        printf("%d/%d\n",fm/p,fz/p);
    }
}
int main()
{
    C[0]=1;
    for(int i=1; i<=12; i++)C[i]=C[i-1]*2;
    scanf("%d",&T);
    while(T--)
    {
        init();
        play();
    }

    return 0;
}

 


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter