【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 [ s 1 ]   x o r   a [ s 2 ]   x o r   a [ s 3 ]   . . .   x o r   a [ s p ]   =   a [ t 1 ]   a n d   a [ t 2 ]   a n d   a [ t 3 ]   . . .   a n d   a [ t q ] 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] f[i][j][3]表示 i ∼ n i\sim n in的数字,异或起来为 j j j,已经到了 一个都没选 / / / 与区间 / / / 异或区间的方案数。
直接转移即可。
注意要压位高精。
时间复杂度 O ( n × S m a x × m a x n ) O(n\times Smax\times maxn) O(n×Smax×maxn)。其中 S m a x = 1024 , m a x n Smax=1024,maxn Smax=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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值