P4876 近似排列计数

来源:互联网 发布:同花顺炒股交易软件 编辑:程序博客网 时间:2024/06/03 06:04

不用看啦,蒟蒻博主没AC,只打了50分的代码!
1:全排列方法暴力判断

#include <cstdio>#include <iostream>#include <cstring> using namespace std;const int mod=1e9+7;bool vis[21];int a[21],ans;void dfs(int x,int p,int k){    if(x==p+1)    {        ans=(ans+1)%mod;        return;    }    int l,r;    l=max(1,x-k),r=min(p,x+k);    if(a[x]) dfs(x+1,p,k);    else    {      if(x>=3)      if(!vis[x-k])//关键:假设这一位没有用这个数,后面的一定不可能用这个,直接返回就好!      {        vis[max(1,x-k)]=1,dfs(x+1,p,k),vis[max(1,x-k)]=0;        return;      }      for(int i=l;i<=r;i++)      {        if(!vis[i]) vis[i]=1,dfs(x+1,p,k),vis[i]=0;      }    }}int main(){    int t;    scanf("%d",&t);    while(t--)    {        memset(a,0,sizeof(a));        memset(vis,0,sizeof(vis));        ans=0;        int n,m,k;        scanf("%d%d%d",&n,&m,&k);        for(int i=1;i<=m;i++)         {            int x,y;            scanf("%d%d",&x,&y);            a[x]=y;            vis[y]=1;         }        if(k==0) ans=1;        else dfs(1,n,k);        printf("%d\n",ans);     }}

2:状压DP
用一个20位串表示1-n是否用过,枚举每个位置,看可以上面填的数是否用过转移即可

#include <cstdio>#include <iostream>#include <cstring> using namespace std;const int mod=1e9+7;const int maxm=(1<<20)+1;int dp[maxm],a[21];int bx[]={-1,0,1,-2,2};void work1(int n,int t){    memset(dp,0,sizeof(dp));    dp[0]=1;    for(int i=1;i<=n;i++)     {        if(a[i])//此处已有数        {            for(int k=(1<<n)-1;k>=0;k--)             if(!(k&(1<<a[i]-1))) //判断有没有用过a[i]这个数             dp[k|(1<<a[i]-1)]=(dp[k|(1<<a[i]-1)]+dp[k])%mod;//没有向加入a[i]的串中转移方案数            continue;        }        int r;        if(t==1) r=2;        else r=4;        for(int k=(1<<n)-1;k>=0;k--)         for(int j=0;j<=r;j++)           {            int x=i+bx[j];//同上            if(x<1||x>n) continue;//不能越界!            if(!(k&(1<<x-1)))  dp[k|(1<<x-1)]=(dp[k|(1<<x-1)]+dp[k])%mod;          }     }     printf("%d\n",dp[(1<<n)-1]);}int main(){    int t;    scanf("%d",&t);    while(t--)    {     int n,m,k;     memset(a,0,sizeof(a));     scanf("%d%d%d",&n,&m,&k);     for(int i=1;i<=m;i++)     {        int x,y;        scanf("%d%d",&x,&y);        a[x]=y;     }     if(k==0) printf("1\n");     else work1(n,k);    }}
原创粉丝点击