zoukankan      html  css  js  c++  java
  • 【JZOJ3889】序列问题【dp】【高精度】

    题目:

    题目链接:https://jzoj.net/senior/#main/show/3889
    小H是个善于思考的学生,她正在思考一个有关序列的问题。
    她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。
    这两个集合要满足以下的条件:
    两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。
    对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。
    对于大小分别为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),你能帮助她吗?


    思路:

    如果满足a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq]a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq]
    ,那么就等价于前者的异或值与后者的与值异或起来等于0。
    所以设f[i][j][3]f[i][j][3]表示inisim n的数字,异或起来为jj,已经到了 一个都没选 // 与区间 // 异或区间的方案数。
    直接转移即可。
    注意要压位高精。
    时间复杂度O(n×Smax×maxn)O(n imes Smax imes maxn)。其中Smax=1024,maxnSmax=1024,maxn是高精度的位数。


    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    
    const int N=1001,Smax=1024,MAXN=40;
    int n,a[N];
    
    struct node
    {
    	ll a[MAXN+1];
    }f[2][Smax][3];
    
    node operator +(node a,node b)
    {
    	node c;
    	ll t=0;
    	for (register int k=MAXN;k>=1;k--)
    	{
    		c.a[k]=a.a[k]+b.a[k]+t;
    		t=c.a[k]/100000000;
    		c.a[k]%=100000000;
    	}
    	return c;
    };
    
    int main()
    {
    	scanf("%d",&n);
    	for (register int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	f[(n+1)&1][Smax-1][0].a[MAXN]=1;
    	for (register int i=n;i>=1;i--)
    	{
    		int id=i&1;
    		memset(f[id],0,sizeof(f[id]));
    		for (register int j=0;j<Smax;j++)
    		{
    			f[id][j][0]=f[id^1][j][0];
    			f[id][j&a[i]][1]=f[id][j&a[i]][1]+f[id^1][j][1]+f[id^1][j][0];
    			f[id][j^a[i]][2]=f[id][j^a[i]][2]+f[id^1][j][2]+f[id^1][j][1];
    			f[id][j][1]=f[id][j][1]+f[id^1][j][1];
    			f[id][j][2]=f[id][j][2]+f[id^1][j][2];
    		}
    	}
    	int i=1;
    	while (!f[1][0][2].a[i] && i<=MAXN) i++;
    	if (i>MAXN) return !printf("0");
    	printf("%lld",f[1][0][2].a[i]);
    	for (i++;i<=MAXN;i++) printf("%08lld",f[1][0][2].a[i]);
    	return 0;
    }
    
  • 相关阅读:
    某个牛人做WINDOWS系统文件详解
    常用ASP脚本程序集锦
    LINUX基础:文件安全与权限
    proftpd+mysql+quota
    apache2.0.49tomcat5.0.19jk2建立virtualHost
    URL Redirection(转) Anny
    顶级域名后缀列表(转) Anny
    \u4E00\u9FA5意义 Anny
    How to POST Form Data Using Ruby(转) Anny
    How to get rid of 'Enter password to unlock your login keyring' in Ubuntu(转) Anny
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11997988.html
Copyright © 2011-2022 走看看