「NOIP模拟赛」序列问题
「题目描述」
小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分把子序列搜索出来然后枚举断点。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define pa pair<int,int> #define inf 1000000000 #define ll long long using namespace std; 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,ans; int a[25],b[25]; void solve(int x) { for(int i=1;i<x;i++) { int s1=0,s2=2047; for(int j=1;j<=i;j++)s1^=b[j]; for(int j=i+1;j<=x;j++)s2&=b[j]; if(s1==s2) { ans++; } } } void dfs(int K,int x) { if(x==n+1) { solve(K-1); return; } b[K]=a[x]; dfs(K+1,x+1); dfs(K,x+1); } int main() { n=read(); for(int i=1;i<=n;i++)a[i]=read(); dfs(1,1); printf("%d\n",ans); return 0; } |
然后异或以及和运算都可以dp出来
f[i][j]表示前i个数集合异或/和的值为j,且i在集合中的方案
但是答案很大,还要压位高精,数组还需要滚动
好麻烦。。
只写了50分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> #define pa pair<int,int> #define inf 1000000000 #define ll long long using namespace std; 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; int a[1005],b[1005]; ll ans,f[1005][2048],g[1005][2048],sum[2048]; int main() { //freopen("sequence.in","r",stdin); //freopen("sequence.out","w",stdout); n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++)b[i]=a[n-i+1]; memset(sum,0,sizeof(sum)); for(int i=1;i<=n;i++) { for(int j=0;j<2048;j++) f[i][j]=sum[j^a[i]]; f[i][a[i]]++; for(int j=0;j<2048;j++)sum[j]+=f[i][j]; } memset(sum,0,sizeof(sum)); for(int i=0;i<n;i++) { for(int j=0;j<2048;j++) g[i+1][j&b[i+1]]+=sum[j]; g[i+1][b[i+1]]++; for(int j=0;j<2048;j++)sum[j]+=g[i+1][j]; } memset(sum,0,sizeof(sum)); for(int i=1;i<n;i++) { for(int j=0;j<2048;j++) sum[j]+=f[i][j]; for(int j=0;j<2048;j++) ans+=sum[j]*g[n-i][j]; } printf("%I64d",ans); return 0; } |
Subscribe