现在的位置: 首页 > 综合 > 正文

【noip模拟赛】序列问题

2017年04月28日 ⁄ 综合 ⁄ 共 2316字 ⁄ 字号 评论关闭

http://hzwer.com/5034.html

位运算相关的状压DP,放一道上来

【题目描述】

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

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

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

  1. 1. 两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。
  2. 2. 对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。
  3. 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分把子序列搜索出来然后枚举断点。。。

#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分

#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;
}

抱歉!评论已关闭.