• HDU 4901 DP


    我觉得这个DP挺难的。。。然而这只是lydrainbowcat学长幻灯片上的第一题……
    明天考试要GG。
    题意:
    给你一个序列,让你选出两个集合S和T。保证S里的数都在T里的数的左边。求一共有多少个集合满足S的异或所得等于T的与的所得,并mod一个大素数。
    思路:
    上课讲的DP,可惜我写了一晚上。。。。。。
    首先我们可以枚举断点。i
    这样就把序列分成了两部分。
    前半部分是集合S
    可以进行DP
    j表示前i个数xor得j的方案数
    f[i][j]=(f[i-1][j]+f[i-1][j*a[i]])%mod
    (上一个状态和a[i]进行异或操作)
    后半部分是集合T
    也可以进行DP
    j表示进行与操作得j的方案数
    d[i][j]=d[i+1][j]
    (显然,如果上一个状态可以到j,这个状态也可以)
    d[i][j]=d[i+1][j],d[i][j&a[i]]=(d[i+1][j]+d[i][j&a[i]])%mod;
    (上一个状态和a[i]进行位与操作)
    所以 ans=((long long)f[i-1][j^a[i]]*d[i+1][j]+ans)%mod;
    (要有强制类型转换)

    // by SiriusRen
    #include <bits/stdc++.h>
    #define F for(int j=0;j<1024;j++)
    using namespace std;
    int cases,n,a[1001],f[1001][1025],d[1001][1025],mod=1e9+7,ans;
    int main(){
        scanf("%d",&cases);
        while(cases--){
            memset(f,0,sizeof(f)),memset(d,0,sizeof(d)),ans=0;
            scanf("%d",&n);
            for(int i=1;i<=n;i++)scanf("%d",&a[i]),d[i][a[i]]++;
            f[0][0]=1;
            for(int i=1;i<=n;i++)
                for(int j=0;j<1024;j++)f[i][j]=(f[i-1][j^a[i]]+f[i-1][j])%mod;
            for(int i=n-1;i>=1;i--){
                F d[i][j]=d[i+1][j],d[i][j&a[i]]=(d[i+1][j]+d[i][j&a[i]])%mod;
                d[i][a[i]]++;
                F ans=((long long)f[i-1][j^a[i]]*d[i+1][j]+ans)%mod;
            }
            printf("%d
    ",ans);
        }
    }

    一不小心还刷了Code Length的第一。
    这里写图片描述

  • 相关阅读:
    知识点
    Python基础 (下)
    Python基础 (上)
    RESTful和SOAP的区别
    Maven
    centos7下配置的php命令
    centos7下的nginx命令配置
    CentOS 7.4下使用yum安装MySQL5.7.20 最简单的
    word下载
    phpExcel导出表格
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532433.html
Copyright © 2020-2023  润新知