NOIP模拟赛-2018.10.22

模拟赛

  今天第一节课是历史,当然是不可能上的,一来到机房发现今天高二考试...

  老师说以后可能还要给高一考...那还不如现在跟着做好了,毕竟在学长学姐中垫底显得没那么丢人

  这套题风格挺奇怪的...为什么前面还是神牛后面直接成牛了...

  T1:http://hzwer.com/5053.html

  题意概述:给出一个长度为$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 }
T1

 

猜你喜欢

转载自www.cnblogs.com/shzr/p/9830919.html