模拟赛
今天第一节课是历史,当然是不可能上的,一来到机房发现今天高二考试...
老师说以后可能还要给高一考...那还不如现在跟着做好了,毕竟在学长学姐中垫底显得没那么丢人
这套题风格挺奇怪的...为什么前面还是神牛后面直接成牛了...
题意概述:给出一个长度为$n$的数列,从某个地方把它分成两部分(均不为空),从前半部分选出一些数,后半部分选出一些数,使得前面这些数的$xor$和等于后面的$and$和,求方案数. $n<=10^3,0<=a_i<1024$
差点被题意杀,其实这个分割点只是限制前后分组顺序的,分割点不同但前后选的人均相同时视为不同的方案.选的人都相同但是分组不同,如$([2,2,3],[3]),([2],[2,2,3])$也算两种方案.
明确了题意就好做多了.可以发现数据范围并不是很大,所以可以枚举断点求方案数.又发现数据范围真的不是很大,所以也可以枚举$xor$和.又发现...再枚举真要超时了.
枚举了这些之后就只需要求出前$i$个中选出一些数使得$xor$和为$x$的方案数,后$i$个中选出一些数使得$and$和为$x$的方案数.这样就比较简单啦!随便$dp$转移一下就行.不过有可能会出现重复方案,对于这个问题固定第一个区间的右端点必选即可.
1 # include <cstdio> 2 # include <iostream> 3 # include <queue> 4 # include <cstring> 5 # include <string> 6 # define R register int 7 # define ll long long 8 # define mod 1000000007 9 10 using namespace std; 11 12 const int maxn=1003; 13 int n,m; 14 int a[maxn],xorr[maxn][1030],andd[maxn][1030],ans; 15 16 int main() 17 { 18 scanf("%d",&n); 19 for (R i=1;i<=n;++i) 20 scanf("%d",&a[i]),m=max(m,a[i]); 21 for (R i=1;i<=n;++i) 22 { 23 xorr[i][ a[i] ]=1; 24 for (R j=0;j<=m;++j) 25 xorr[i][ a[i]^j ]=(xorr[i][ a[i]^j ]+xorr[i-1][j])%mod; 26 for (R j=0;j<=m;++j) 27 xorr[i][j]=(xorr[i][j]+xorr[i-1][j])%mod; 28 } 29 for (R i=n;i>=1;--i) 30 { 31 andd[i][ a[i] ]=1; 32 for (R j=0;j<=m;++j) 33 andd[i][ a[i]&j ]=(andd[i][ a[i]&j ]+andd[i+1][j])%mod; 34 for (R j=0;j<=m;++j) 35 andd[i][j]=(andd[i][j]+andd[i+1][j])%mod; 36 } 37 for (R i=1;i<n;++i) 38 for (R j=0;j<=m;++j) 39 ans=(1LL*(xorr[i][j]-xorr[i-1][j]+mod)*andd[i+1][j]%mod+ans)%mod; 40 printf("%d",ans); 41 fclose(stdin); 42 fclose(stdout); 43 return 0; 44 }