给你一个串数字,然后让你在这里面挑取两个集合S ,T,集合的要求是
(1)不能为空
(2)S集合的所有元素必须在T集合的左边
(3)S集合的XOR == T集合的AND
问可以找到多少组这样的集合对。
思路:
两种方法,一个是枚举T集合的第一个元素,或者是枚举S集合的最后一个元素,首先我们开四个数组
sum_xor[1002][2050] 记录从左到右直到第i个节点的时候的j这个数字有多少种可能
now_xor[1002][2050] 记录从左到右直到第i个节点并且必须选择i这个节点时j出现的次数sum_and[1002][2050] 同理.(只不过是n-->1)..
now_and[1002][2050] 同理. (只不过是n-->1)..
更新数组的时候可以想象下01背包,当前的状态由上一步的所有可能状态和当前的这个数字组合出来后得到的新状态,对于sum_..记得加上上一步的所有状态,这个题目关键就是枚举的时候不能出现重复的集合对。然后我们枚举一遍就ok了,两种枚举方法,第一种是sum_xor,now_and两个状态组合,另一
个是now_xor ,sum_and组合,给个关键的代码for(i = 1 ;i <= n ;i ++)
{
now_xor[i][num[i]] ++;//自己这个状态
sum_xor[i][num[i]] ++;//自己这个状态
for(j = 0 ;j <= 2048 ;j ++)
{
if(sum_xor[i-1][j])//如果之前有j这个状态
{
now_xor[i][j^num[i]] += sum_xor[i-1][j];//新状态的增加值
sum_xor[i][j^num[i]] += sum_xor[i-1][j];//新状态的增加值
sum_xor[i][j] += sum_xor[i-1][j];//当前的和也要加上之前的所有可能和
//然后都MOD一下
}
}
}
AND的同理...
(1)枚举T集合的第一个
for(i = 2 ;i <= n ;i ++)
{
for(j = 0 ;j <= 2048 ;j ++)
if(sum_xor[i-1][j] && now_and[i][j])
ans = (sum_xor[i-1][j] * now_and[i][j]) % MOD;
}
(2)枚举S集合的最后一位
for(i = 1 ;i <= n - 1 ;i ++)
{
for(j = 0 ;j <= 2048 ;j ++)
if(now_xor[i-1][j] && sum_and[i][j])
ans = (now_xor[i-1][j] * sum_and[i][j]) % MOD;
}
#include<stdio.h> #include<string.h> #define MOD (1000000000 + 7) __int64 sum_xor[1002][2050] ,now_xor[1002][2050]; __int64 sum_and[1002][2050] ,now_and[1002][2050]; __int64 num[1002]; int main () { int i ,j ,n ,t; scanf("%d" ,&t); while(t--) { scanf("%d" ,&n); for(i = 1 ;i <= n ;i ++) scanf("%I64d" ,&num[i]); memset(sum_xor ,0 ,sizeof(sum_xor)); memset(now_xor ,0 ,sizeof(now_xor)); for(i = 1 ;i <= n ;i ++) { sum_xor[i][num[i]] ++; now_xor[i][num[i]] ++; for(j = 0 ;j <= 2048 ;j ++) if(sum_xor[i-1][j]) { now_xor[i][j^num[i]] += sum_xor[i-1][j]; sum_xor[i][j^num[i]] += sum_xor[i-1][j]; sum_xor[i][j] += sum_xor[i-1][j]; now_xor[i][j^num[i]] %= MOD; sum_xor[i][j^num[i]] %= MOD; sum_xor[i][j] %= MOD; } } memset(sum_and ,0 ,sizeof(sum_and)); memset(now_and ,0 ,sizeof(now_and)); for(i = n ;i >= 1 ;i --) { sum_and[i][num[i]] ++; now_and[i][num[i]] ++; for(j = 0 ;j <= 2048 ;j ++) if(sum_and[i+1][j]) { now_and[i][j&num[i]] += sum_and[i+1][j]; sum_and[i][j&num[i]] += sum_and[i+1][j]; sum_and[i][j] += sum_and[i+1][j]; now_and[i][j&num[i]] %= MOD; sum_and[i][j&num[i]] %= MOD; sum_and[i][j] %= MOD; } } __int64 ans = 0; for(i = 2 ;i <= n ;i ++) { for(j = 0 ;j <= 2048 ;j ++) if(sum_xor[i-1][j] && now_and[i][j]) ans = (ans + sum_xor[i-1][j] * now_and[i][j]) % MOD; } printf("%I64d " ,ans); } return 0; }