wang_sj的博客

穷且益坚,不坠青云之志

序列问题

题目描述
小H是个善于思考的学生,她正在思考一个有关序列的问题。

她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。

这两个集合要满足以下的条件:

  1. 两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。

  2. 对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。

  3. 对于大小分别为p, q的集合S与T,满足

        a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq].
    

小H想知道一共有多少对这样的集合(S,T),你能帮助她吗?

输入
第一行,一个整数n

   第二行,n个整数,代表ai。

输出
仅一行,表示最后的答案。

样例输入
4
1 2 3 3
样例输出
4
提示
【样例解释】

S = {1,2}, T = {3}, 1 ^ 2 = 3 = 3 (^为异或)

S = {1,2}, T = {4}, 1 ^ 2 = 3 = 3

S = {1,2}, T = {3,4} 1 ^ 2 = 3 & 3 = 3 (&为与运算)

S = {3}, T = {4} 3 = 3 = 3

【数据范围】

30%: 1 <= n <= 10


60%: 1 <= n <= 100


100%: 1 <= n <= 1000, 0 <= ai < 1024

题解
30%:枚举每个数所在的集合或者不选,然后判定即可。复杂度 O(n*3^n)。
60%: Dp,两个数相等就相当于两个数的 xor 为 0。设 f[i][j][k=0..2]代表 处理到第 I 个数,
如果 k = 1 代表 and 值为 j,如果 k = 2 代表 xor 值为 j,如果 k = 0 则代表一个元素都没
取。所以很容易得到方程:
f[i][j][0] = f[i + 1][j][0]
f[i][j & ai][1] = f[i + 1][j][1] + f[i + 1][j][0] + f[i + 1][j & ai][1]
f[i][j ^ ai][2] = f[i + 1][j][1] + f[i + 1][j][2] + f[i + 1][j ^ ai][2];
最后 f[1][0][2]就是答案, 复杂度为 O(n * 1024 * 3)
DP 还可以分开用 f[i][j]和 g[i][j]表示前 i 个 xor 值为 j,后 i 个 and 值为 j 的方案数,
随后枚举分界点 k 来求总方案数。复杂度 O(n * 1024 * 3)。
100%:满分数据需要高精,答案位数较大,需要进行压位来防止 TLE,因为不知道答案的
位数究竟多大,压位后高精数组仍需要开的较大一些,所以原 DP 的数组滚动即可。

代码(自己打的压位高精,比标程慢太多)

#include<bits/stdc++.h>
#define ll long long
#define W 1000000000
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,p[1005];
struct node{
    int len,a[40];
    inline void print()
    {
        printf("%d",a[len]);
        for (int i=len-1;i;i--)
            printf("%09d",a[i]);
        return;
    }
}f[2][1025][3];
node operator+(node a,node b)
{
    int c[100],z=0,i;
    a.len=max(1,a.len);
    b.len=max(1,b.len);
    for (i=1;i<=a.len||i<=b.len;i++)
    {
        c[i]=a.a[i]+b.a[i]+z;
        z=c[i]/W;
        c[i]%=W;
    }
    int l=max(a.len,b.len);
    i=l+1;
    while (z)
    {
        c[i]=z;
        z=c[i]/W;
        c[i]%=W;
        i++;
    }
    a.len=i-1;
    for (i=1;i<=a.len;i++)
        a.a[i]=c[i];
    return a;
}
int main()
{
    n=read();m=1024;
    for (int i=n;i;i--) p[i]=read();
    f[0][1023][0].a[1]=1;
    int pre=0,suc=1;
    for (int i=1;i<=n;i++)
    {
        suc=pre^1;
        for (int j=0;j<m;j++)
            for (int k=0;k<=2;k++)
                f[suc][j][k]=f[pre][j][k];
        for (int j=0;j<m;j++)
        {
            int a=p[i]&j,x=p[i]^j;
            f[suc][a][1]=f[suc][a][1]+f[pre][j][0]; 
            f[suc][a][1]=f[suc][a][1]+f[pre][j][1]; 
            f[suc][x][2]=f[suc][x][2]+f[pre][j][1]; 
            f[suc][x][2]=f[suc][x][2]+f[pre][j][2];
        }
        pre=suc;
    }
    f[pre][0][2].print();
    return 0;
}

标算

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int W=1e9;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int n,m,p[1005];
struct node{
    int len,a[40];
    node():len(1){memset(a,0,sizeof(a));}
    inline void operator+=(node &b)
    {
        b.len>len?len=b.len:0;
        for (int i=1;i<=len;i++) {
            a[i]+=b.a[i];
            if (a[i]>=W) a[i+1]++,a[i]-=W;
        }
        if (a[len+1])len++;
        return ;
    }
    inline void print()
    {
        printf("%d",a[len]);
        for (int i=len-1;i;i--)
            printf("%09d",a[i]);
        return;
    }
}f[2][1025][3];
int main()
{
    n=read();m=1024;
    for (int i=n;i;i--) p[i]=read();
    f[0][1023][0].a[1]=1;
    int pre=0,suc=1;
    for (int i=0;i<n;i++)
    {
        suc=pre^1;
        for (int j=0;j<m;j++)
            for (int k=0;k<=2;k++)
                f[suc][j][k]=f[pre][j][k];
        for (int j=0;j<m;j++)
        {
            int a=p[i+1]&j,x=p[i+1]^j;
            f[suc][a][1]+=f[pre][j][0]; f[suc][a][1]+=f[pre][j][1]; 
            f[suc][x][2]+=f[pre][j][1]; f[suc][x][2]+=f[pre][j][2];
        }
        pre=suc;
    }
    f[pre][0][2].print();
    return 0;
}
阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/w_yqts/article/details/75127567
个人分类: dp 杂题
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭