hunnu 11463 信封问题 (找规律||搜索)

来源:互联网 发布:网络小说家怎么赚钱 编辑:程序博客网 时间:2024/05/28 17:04

题目链接:点击打开链接

题目大意:全错排问题,指定了某些信封装的信的对于编号,求全错排的解~~~~

刚开始拿到这个题目感觉无从下手,无法保存搜索过程的状态,遂找到对应答案相同的解的特点,打表找到了某个稀里糊涂的规律,2333

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>using namespace std;typedef long long llt;const int MAXN=1100;const int MOD=1000000007;int env[MAXN];llt dp[MAXN][MAXN];void init(){dp[0][0]=1;dp[1][0]=0;dp[1][1]=0;dp[2][1]=1;for(int i=2;i<=1000;i++)dp[i][0]=(dp[i-1][0]+dp[i-2][0])*(i-1)%MOD;for(int i=4;i<=1000;i+=2) dp[i][i/2]=dp[i-2][(i-2)/2]*(i/2)%MOD;for(int j=1;j<=500;j++)for(int i=2*j+1;i<=1000;i++)dp[i][j]=((i-j)*dp[i-1][j]%MOD+MOD-j*dp[i-3][j-1]%MOD)%MOD;}int main() {    int n;    init();    while(scanf("%d",&n)!=EOF)    {    int ret=0,hook=0;    bool flag=false;    for(int i=1;i<=n;i++)    {    scanf("%d",&env[i]);    if(env[i]) ret++;    if(env[i]==i) flag=true;    }    if(flag)    {    puts("0");    continue;    }    for(int i=1;i<=n;i++)     if(env[env[i]]) hook++;    printf("%d\n",dp[n-hook][ret-hook]);    }    return 0;}
后面还发现另一种容易理解的解法~~~

#include <cstdio>#include <cstring>using namespace std;int a[1010];bool f[1010];__int64 dp[1010][1010];const __int64 mod=1000000007LL;__int64 dfs(int,int);void debug(){    for(int i=0;i<=9;i++)    {        for(int j=0;j<=i/2;j++)          printf("DP[%d][%d] :%-4d ",i,j,dfs(i,j));        putchar('\n');    }}//a个不能放在其原本位置,b个可以放在任意位置__int64 dfs(int a,int b){    if(a<0||b<0)        return 0;    if(dp[a][b]>=0)        return dp[a][b];    __int64 ret;    //如果b的数量为0,就变成了全错排问题    if(b==0) ret=(a-1)*(dfs(a-1,0)+dfs(a-2,0));    //else ret=dfs(a+1,b-1)+dfs(a,b-1);//玄学问题,这个也能过,不过过程不理解    else ret=a*dfs(a-1,b)+b*dfs(a,b-1);    ret%=mod;    return dp[a][b]=ret;}int main(){    int i,n,cnta,cntb;    //freopen("1.in","r",stdin);    //freopen("1.out","w",stdout);    bool flag;    memset(dp,-1,sizeof(dp));    dp[0][0]=1;    debug();    while(scanf("%d",&n)!=EOF)    {          memset(f,0,sizeof(f));          for(i=1;i<=n;i++)               scanf("%d",&a[i]);          cnta=cntb=0;          flag=1;          for(i=1;i<=n;i++)            if(a[i]!=0)            {               if(f[a[i]]==1||a[i]==i) flag=0;               f[a[i]]=1;            }          for(i=1;i<=n;i++)               if(a[i]==0)               {                    if(f[i]==0) cnta++;                    else  cntb++;               }          ///cnta表示不能放在其原本位置的信封的个数          ///cntb表示可以随意放置的信封数量          if(!flag) printf("0\n");          else printf("%I64d\n",dfs(cnta,cntb));    }    return 0;}


(最近写题解越来越不走心了,233333333,如果有HUNNU的小伙伴在有生之年能看到我这篇题解,看不懂就直接来问我吧,233333333~~~~~)

原创粉丝点击