序列问题
来源:互联网 发布:中医 数据库 编辑:程序博客网 时间:2024/06/06 00:12
题目描述
小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),你能帮助她吗?
输入
第一行,一个整数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 <= 1060%: 1 <= n <= 100100%: 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 1000000000using 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 longusing 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;}
- 序列问题
- 序列化问题
- 序列化NotSerializableException问题
- 最大子序列问题
- 最大子序列问题
- java 序列化 问题
- 括号序列问题
- 序列化问题!Datatable
- 最大子序列问题
- java序列化问题
- 序列化问题
- oracle序列问题
- HashSet序列化问题
- 最大子序列问题
- 出栈序列问题
- 计算机字节序列问题
- 序列化--画图问题
- oracle 序列问题
- 用python写爬虫,爬取清纯妹子网站
- Spring歪解
- 关于iOS中延迟执行的几种方法
- JVM 的 工作原理,层次结构 以及 GC工作原理
- c++ GUI Qt4 的关于forward declaration of "class xxx 的错误"
- 序列问题
- 12.Scala中的继承:超类的构造、重写字段、重写方法代码实战
- 常用数组扩展
- mysql命令行不用输入用户名和密码的方法
- leetcode:Odd Even Linked List
- 分析if__name__==__main__
- MySQL前缀索引和索引选择性
- Python读写/追加excel文件Demo
- jira 安装 破解 汉化