多校3 hdu 6321 Problem C. Dynamic Graph Matching (状态dp)(注意取模函数超时)

题目链接:哆啦A梦传送门

题意:给n个点,m个操作,每次为 + u v或者 - u v,+ 表示点u与点v之间连一条边,反之 - 亦然。每次操作完成后,输出n/2个数,分别表示当前选出1条无公共端点的边,2条无公共端点的边,3条.....n/2条无公共端点边时分别有多少种不同的选择。

 

题解:参考博客:https://blog.csdn.net/paradise_tht/article/details/81385383

官方解释:

详情见代码:

还需注意一点的是,取模是尽量不要用取模函数,这里我就是因为这而被T。

 

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

typedef long long LL;
const int maxn=1300;
LL mod=1e9+7;
LL dp[maxn][12]; ///dp[i][j]表示在状态i下(也就是有多少个点),j条无公共端点的边有多少种不同的选择
int cnt[maxn];
char op[10];

int main()
{

    for(int i=1;i<maxn;i++) ///初始化,预处理cnt[i]表示i的二进制有多少个1
        cnt[i]=cnt[i>>1]+(i&1);

    int ncase;
    scanf("%d",&ncase);

    int n,m;
    while(ncase--)
    {
        scanf("%d%d",&n,&m);
        memset(dp,0,sizeof(dp));



        int u,v,uv,S=(1<<n)-1; ///S表示满点状态

        for(int i=0;i<=S;i++)
            dp[i][0]=1;
        while(m--)
        {
            scanf("%s%d%d",op,&u,&v);
            u--;v--;
            uv=(1<<u)|(1<<v); ///将u,v点转化成二进制uv,表示含有u,v点的状态

            for(int i=S;i>=0;i--) ///我们从大(满点)到小dp,
            {
                if((i&uv)!=uv) continue; ///此状态不包含uv,故跳过

                for(int j=1;j<=cnt[i];j++) 
                {
                    if(op[0]=='+') dp[i][j]+=dp[i^uv][j-1];
                    else dp[i][j]+=(mod-dp[i^uv][j-1]);

                    if(dp[i][j]>=mod) ///取模,不能用下面直接模,会T
                    dp[i][j]-=mod;
                    ///因为下面的方法调用了基本的取模函数和除法函数,既有函数调用,还有很多汇编代码和寄存器参与运算,
                    ///而上面的方法则仅仅是几句相关的汇编,代码更简洁、效率更高。
//                        dp[i][j]%=mod;
//            printf("s=%d,j=%d,uv=%d,%d %d\n",i,j,i^uv,dp[i][j],dp[i^uv][j-1]);

                }
            }

            for(int i=1;i<n/2;i++)
                printf("%lld ",dp[S][i]);
            printf("%lld\n",dp[S][n/2]);
        }
    }
    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值