首先吐槽一下这个神一样的题目前缀,特么一直在强调萝莉控是闹哪样啊喂(╯‵□′)╯︵┻━┻
题意不难,从一个数列中选出一部分作为S,S的元素进行 ‘异或’ 操作,在选出一部分作为T,T里的元素进行 ’与‘ 操作,要求S的元素必须在T的元素的左边。
最初没有想到用DP写,因为没有想到用下标表示数字,其实用用二维数组DP,横坐标表示操作到第几个数,纵坐标储存该数字得到多少次,最开始把初状态放进去就好,最后对应位置相乘加起来就好了,G++TLE了,换成C++2437ms过了,另外写的时候思路还不是很清晰,代码很乱。
#include <iostream>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <cstdlib>
#include <iomanip>
using namespace std;
const int mod=1000000000+7;
long long dp1[1111][1111];
long long dp3[1111][1111];
long long dp2[1111][1111];
long long m1[2048];
long long m2[2048];
int a[1111];
int n;
long long sum;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
memset(dp3,0,sizeof(dp3));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
dp1[1][a[1]]=1;//初状态处理
dp3[1][a[1]]=1;
//dp1[1][0]=1;
dp2[n][a[n]]=1;
//dp2[n][0]=1;
for(int i=2;i<n;i++)
{
dp3[i][a[i]]+=1;//用来表示前几个都不取的情况
dp1[i][a[i]]+=1;
memset(m1,0,sizeof(m1));
for(int j=0;j<=1024;j++)
{
if(dp1[i-1][j]!=0)
{
dp3[i][a[i]^j]+=dp1[i-1][j];//用另一个DP储存,因为最后处理时要求最后一个必须取到
dp1[i][a[i]^j]+=dp1[i-1][j];
dp1[i][a[i]^j]%=mod;
dp3[i][a[i]^j]%=mod;
m1[j]=dp1[i-1][j];
m1[j]%=mod;
}
}
for(int j=0;j<=1024;j++)
{
dp1[i][j]+=m1[j];
dp1[i][j]%=mod;//处理到第i个的总情况
}
}
for(int i=n-1;i>1;i--)
{
dp2[i][a[i]]+=1;//用来表示前几个都不取的情况
memset(m2,0,sizeof(m2));
for(int j=0;j<=1024;j++)
{
if(dp2[i+1][j]!=0)
{
dp2[i][a[i]&j]+=dp2[i+1][j];//后面的只需要保证不为空就行了,不需要特殊处理
dp2[i][a[i]&j]%=mod;
m2[j]=dp2[i+1][j];
m2[j]%=mod;
}
}
for(int j=0;j<=1024;j++)
{
dp2[i][j]+=m2[j];
dp2[i][j]%=mod;
}
}
sum=0;
for(int i=1;i<n;i++)
{
for(int j=0;j<=1024;j++)
{
if(dp3[i][j]&&dp2[i+1][j])
{
sum+=dp3[i][j]*dp2[i+1][j];//对应位置相乘相加,+1刚好是所有的情况
sum%=mod;
}
}
//cout<<sum<<endl;
}
cout<<sum<<endl;
}
}