标签:blog os io 数据 for 代码 div amp
题意:有n个数(n<=1000),每个数<1024,现在给出a、b两个集合,需要你从这n个数中取出一些数,将取出的数放在a集合或者b集合,a集合的数的最大下标严格小于b集合所取的数的最小下标,然后a集合的数进行抑或操作,b集合的数进行与操作,问你操作后,这两个数相等,问你有多少种不同的方法。
思路:我发现暑假集训开始到现在,我一直在酱油中,状态根本没回升--以前遇到这样的题目,果断是可以出的,而在比赛的时候,还是队友提示,我才想到思路的。
其实,我们可以开个二维数组来记录在第i个数放入a集合时所取到的数的种数......与就是dp[1005][1024]
这样,不仅记录了在a集合取第i个数的时候,这个数是否存在,还记录了这个数存在的情况下,出现的次数。。。。。。
然后,我还开了个数组,记录b集合的。
这里需要注意,要将b集合的数据,全部集中到一起,而a集合的数据则不必,只需要再开一个数组,将a集合前面所有出现过的数以及次数保存下来,在去第i个数时,不仅
要判断i-1的情况,还要判断i-2,i-3,i-4.....1的所有情况,但是不能像b集合那样操作,将所有数据都集中在一起,那样会多的。
只能是再开一个数组,记录a集合i-1以前所有出现过的数据。
ac代码:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef __int64 ss;
const ss mod=1000000007;
int dp[1005][1080],t[1005][1080],n,s[1005],maxn;
int p[1005][1080];
/*
dp数组是用来记录a集合中与前i-1个数第i个数异或的结果以及次数
p数组,用来记录a集合中i-1之前出现的数的次数
t数组,用来记录b集合中i到n之间所有出现的结果以及次数,不与i异或,但
也出现了的结果,要是记录在t数组中
*/
int main()
{
int text;
scanf("%d",&text);
while(text--)
{
memset(dp,0,sizeof(dp));
memset(t,0,sizeof(t));
memset(p,0,sizeof(p));
scanf("%d",&n);
maxn=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&s[i]);
maxn|=s[i];
}
dp[1][s[1]]=1;
t[n][s[n]]=1;
p[1][s[1]]=1;
for(int i=2;i<n;i++)
{
dp[i][s[i]]++;
p[i][s[i]]++;
p[i][s[i]]%=mod;
dp[i][s[i]]%=mod;
for(int j=0;j<=maxn;j++)
{
p[i][j]+=p[i-1][j];
p[i][j]%=mod;
if(dp[i-1][j])
{
int tmp=j^s[i];
dp[i][tmp]+=dp[i-1][j];
p[i][tmp]+=dp[i-1][j];
p[i][tmp]%=mod;
dp[i][tmp]%=mod;
}
if(i-2>0)
{
if(p[i-2][j])
{
ss tmp=j^s[i];
dp[i][tmp]+=p[i-2][j];
p[i][tmp]+=p[i-2][j];
p[i][tmp]%=mod;
dp[i][tmp]%=mod;
}
}
}
}
for(int i=n-1;i>1;i--)
{
t[i][s[i]]++;
t[i][s[i]]%=mod;
for(int j=0;j<=maxn;j++)
{
t[i][j]+=t[i+1][j];
t[i][j]%=mod;
if(t[i+1][j])
{
ss tmp=s[i]&j;
t[i][tmp]+=t[i+1][j];
t[i][tmp]%=mod;
}
}
}
ss ans=0;
for(int i=1;i<n;i++)
{
for(int j=0;j<=maxn;j++)
{
ans+=(((__int64)dp[i][j]*(__int64)t[i+1][j])%mod);
ans%=mod;
}
}
printf("%I64d\n",ans);
}
return 0;
}
标签:blog os io 数据 for 代码 div amp
原文地址:http://www.cnblogs.com/ziyi--caolu/p/3888670.html