暑假培训第一天~
不敢正视的lyd大神…..
然后上手写的第一道题,就这么的打击我…… 真是混不下去了
题意:
有n个数,从n个数中选出两个集合s和集合t,保证原序列中,集合s中的元素都在
集合t中元素的左边。且要求集合s中元素做抑或运算的值与集合t中元素做与运算的
值相等。问能选出多少种这样的集合s和t。
分析:
分析倒不是太难.如题,肯定是2段序列左一段,右一段.左边那一段呢是XoR这个还不算难,因为异或两边就有一样了.方程见代码
右边呢,稍微麻烦一些.
dp[i][j]表示左边界是i,和是j的方案数
就是1.单个他自己,也是一种方案
2.当前的j &a[i] 是i-1 j,和i,.j&a[i]
3.当前的j是i,j+i+1,j[我是倒叙拍的]
但是这样还会有重复的,所以让XOR 那边最后一个数必须被选,防重
Tips define 只是字符的替换,并不能够like const的一样[害惨本人了]@SiriusRen 感谢
瞧代码:
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define mod 1000000007; //这样是没问题的
typedef long long ll;
int a[1010];
int d[1010][1025],f[1010][1025],r[1010][1025];
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
memset(d,0,sizeof(d));
/*********************XOR******************/
d[0][0] = 1;
for(int i=1;i<=n;i++)
{
for(int j=0;j<1024;j++)
{
d[i][j] = (d[i-1][j]+d[i-1][j^a[i]])%mod;
}
for(int j=0;j<1024;j++)
r[i][j] = d[i-1][j^a[i]]; //去重
}
/***********************AND********************/
memset(f,0,sizeof(f));
for(int i=n;i>=1;i--)
{
f[i][a[i]]++;
for(int j=0;j<1024;j++)
{
f[i][j&a[i]] = (f[i][j&a[i]]+f[i+1][j])%mod;
f[i][j] = (f[i][j]+f[i+1][j])%mod;
}
}
/*************************Solve*********************/
int ans = 0;
for(int i=1;i<=n-1;i++)
{
for(int j=0;j<1024;j++)
{
if(r[i][j] && f[i+1][j])
ans = (ans+(ll)r[i][j]*f[i+1][j])%mod;
}
}
printf("%d\n",ans);
}
return 0;
}