「csp-s模拟测试(9.18)」Set·Read·Race

昨天考试考得有点迷???

一看内存限制,T1 64MB T2 16MB 当场懵比.........

T1 set

考场打的背包问题和随机化,其实能randA掉,但不小心数组开小了????(长记性!!!!!

正解的话因为每个前缀只需mod%n,所以有n+1个数,其中一定有重复的

所以就可以O(n)扫了

其实正解不难就是没有细想

 1 #include<bits/stdc++.h>
 2 #define MAXN 1100
 3 using namespace std;
 4 int read(){
 5     int x=0;char c=getchar();
 6     while(c<'0'||c>'9')c=getchar();
 7     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
 8     return x;
 9 }
10 int n;
11 int a[MAXN*MAXN];
12 struct node{int id,w;}e[1000001];
13 int ans[MAXN];
14 int pre[MAXN][1001];
15 bool biao[2][MAXN];
16 void work(){
17      for(int i=1;i<=n;++i){
18          e[i].id=i;e[i].w=a[i];
19      }
20      for(int i=1;i<=20000;++i){
21          if(clock()>990000){
22             printf("-1\n");
23             return ;
24          }
25          random_shuffle(e+1,e+n+1);
26          int ok=0;int me=0;
27          for(int j=1;j<=n;++j){
28              me=(me+(e[j].w%n))%n;
29              if(me==0){
30                 ok=j;break;
31              }
32          }
33          if(ok==0)continue;
34          printf("%d\n",ok);
35          for(int j=1;j<=ok;++j)printf("%d ",e[j].id);
36          return ;
37      }
38 }
39 signed main(){
40     n=read();
41     for(int i=1;i<=n;++i){
42         a[i]=read();a[i]%=n;
43     }
44     if(n>1000){
45         work();
46         return 0;
47     }
48     int now=1;int last=0;
49     biao[last][0]=1;
50     for(int i=1;i<=n;++i){
51         for(int j=0;j<n;++j){
52             if(biao[last][j]){
53                biao[now][j]=1;
54                pre[i][j]=0;
55             }
56             if(biao[last][j]){
57                biao[now][(j+a[i])%n]=1;
58                pre[i][(j+a[i])%n]=i;
59             }
60         }
61         swap(now,last);
62         memset(biao[now],0,sizeof(biao[now]));
63     }
64     swap(now,last);
65     if(biao[now][0]==0){printf("-1\n");return 0;}
66     now=0;
67     for(int i=n;i>=1;--i){
68         if(pre[i][now]!=0)ans[++ans[0]]=pre[i][now];
69         now=(now-a[pre[i][now]]%n+n)%n;        
70     }
71     if(ans[0]==0){printf("-1\n");return 0;}
72     printf("%d\n",ans[0]);
73     for(int i=1;i<=ans[0];++i){
74         printf("%d ",ans[i]);
75     }
76     cout<<endl;
77 }
78 /*
79 g++ pai.cpp -o pai
80 ./pai
81 g++ a.cpp -o a
82 ./a
83 */
考场随机化暴力
 1 #include<bits/stdc++.h>
 2 #define MAXN 1100000
 3 #define int long long
 4 using namespace std;
 5 int vis[MAXN];int n,a[MAXN];
 6 signed main(){
 7      scanf("%lld",&n);
 8      vis[0]=0;
 9      for(int i=1;i<=n;++i){
10          scanf("%lld",&a[i]);
11      }int sum=0;
12      for(int i=1;i<=n;++i){
13          sum=(a[i]+sum)%n;
14          if(vis[sum]!=0){
15             printf("%lld\n",i-vis[sum]);
16             for(int j=vis[sum]+1;j<=i;++j){
17                 printf("%lld ",j);
18             }
19             return 0;
20          }
21          vis[sum]=i;
22      }
23 }
View Code

 

T2 read

考场时看出了答案其实就是2*maxn_sum-N-1,至于证明,除非最后时只剩一种类型的书了,不然肯定能接着放

那么我们就可以直接判断了

考场没算清内存其实1e6的数据是可以开数组的

对于正解,定义一个id,cnt

我们对于每个新出现的数,当cnt=0时id=当前数,不然id=当前数cnt++;否则cnt--;

可以发现如果存在解的话,id一定为最大出现次数的值,但是因为可能中间存在非最大值之间互相抵消的情况

所以还要再扫一边,判断当前值出现次数

 1 #include<bits/stdc++.h>
 2 #define MAXN 1100
 3 #define int long long
 4 using namespace std;
 5 int M,N,K;
 6 int co[MAXN],x[MAXN],y[MAXN],z[MAXN];int a[MAXN];
 7 int maxn_sum=0;int maxn;int S;
 8 signed main(){      
 9       scanf("%lld%lld",&M,&K);
10       S=(1<<K)-1;
11       for(int i=1;i<=M;++i)scanf("%lld",&co[i]);
12       for(int i=1;i<=M;++i)scanf("%lld",&x[i]);
13       for(int i=1;i<=M;++i)scanf("%lld",&y[i]);
14       for(int i=1;i<=M;++i)scanf("%lld",&z[i]);
15       N=0;int cnt=0;int id=0;
16       for(int i=1;i<=M;++i){          
17           long long last=x[i];
18           N++;
19           if(cnt==0){cnt=1;id=last;}
20           else if(id==last){cnt++;}
21           else if(id!=last){cnt--;}
22           for(int j=1;j<co[i];++j) {
23           last=(last*y[i]+z[i])&S;
24           N=N+1;
25               if(cnt==0){cnt=1;id=last;}
26               else if(id==last){cnt++;}
27               else if(id!=last){cnt--;}
28         }
29       } 
30       if(cnt<1){printf("0\n");return 0;}
31       cnt=0;N=0;
32       for(int i=1;i<=M;++i){
33           long long last=x[i];
34           N++;
35           if(id==last){cnt++;}
36           for(int j=1;j<co[i];++j) {
37           last=(last*y[i]+z[i])&S;
38           N=N+1;
39               if(id==last){cnt++;}
40         }          
41       }
42       if(2*cnt-N-1>0){printf("%lld\n",2*cnt-N-1);}
43       else printf("0\n");
44       /*scanf("%lld",&N);
45       int cnt=0;int id=0;
46       for(int i=1;i<=N;++i){scanf("%lld",&a[i]);}
47       for(int i=1;i<=N;++i){
48           long long last=a[i];     
49           if(cnt==0){cnt=1;id=last;}
50           else if(id==last){cnt++;}
51           else if(id!=last){cnt--;}         printf("i=%lld\n",i);  
52       }
53       if(cnt-1>0)printf("%lld\n",cnt-1);
54       else printf("%lld\n",cnt);
55       */
56 }
57 /*
58 22
59 1 3 3 3 3 2 2 2 2 1 1 1 1 1 1 1 1 1  1 1 1 1 
60 */
View Code

 

T3 race

咕了.............

不咕。

一道trie树好题,想了两节课,(在语文课上想题效率很高QAQ)

首先对于x^2的转化:

   既然是排名,我们可以考虑成x^2,是每个大于他的数的集合相乘,即(x1+x2+x3+x4.....)*(x1+x2.......)

(其中每个xi都为1),那么结果可以看成任意一个点对的贡献为一,答案就是点对的个数

既然结果是求异或和,我们联想到trie树(这样说有些牵强.......)

无论如何我们先建棵trie树

那么从1-n的每个i,我们统计这个节点时单独考虑每一位的贡献,我们枚举一个j,一个k

j(k)上的数表示在M-1位到j+1位的数与a[i]的这些位的数相等,那么如果使j,k同时大于a[i],我们只需

确定好异或的第j,k位上的数,其他数随意,这样这两位上的数对他的贡献就是两个位的指针上的size*(1<<M-2)

当j==k时乘的变成(1<<M-1),因为只需确定一位

 

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define MAXN 210000
 4 using namespace std;
 5 int fa[MAXN][31];
 6 struct node{
 7      int ch[2];
 8      int size;
 9 }t[MAXN*20];int n,M;
10 const int mod=1e9+7;
11 int tot=1;int a[MAXN];
12 void insert(int x){
13      int p=1;t[p].size++;fa[x][M]=1;
14      for(int i=M-1;i>=0;--i){
15          int me=(a[x]>>i)&1;
16          if(t[p].ch[me]==0)t[p].ch[me]=++tot;
17          p=t[p].ch[me];
18          t[p].size++;
19          fa[x][i]=p;
20      }
21 }
22 int ans[MAXN];
23 void work(int x){
24      for(int i=0;i<=M-1;++i){
25          int me1=0,find1=0;int me2=0,find2=0;
26          for(int j=0;j<i;++j){
27              me1=(a[x]>>i)&1;me2=(a[x]>>j)&1;
28              me1^=1;me2^=1;
29              find1=fa[x][i+1];find2=fa[x][j+1];
30              ans[x]=(ans[x]+2*t[t[find1].ch[me1]].size*t[t[find2].ch[me2]].size%mod*(1ll<<(M-2ll)))%mod;
31          }
32          me1=(a[x]>>i)&1;me1^=1;
33          find1=fa[x][i+1];
34          ans[x]=(ans[x]+t[t[find1].ch[me1]].size*t[t[find1].ch[me1]].size%mod*(1<<(M-1)))%mod;
35      }
36 }
37 int sum=0;
38 signed main(){
39      scanf("%lld%lld",&n,&M);
40      for(int i=1;i<=n;++i){
41          scanf("%lld",&a[i]);
42      }
43      for(int i=1;i<=n;++i){insert(i);}
44      for(int i=1;i<=n;++i){work(i);}
45      for(int i=1;i<=n;++i){
46          sum^=ans[i];
47      }
48      printf("%lld\n",sum);
49 }
View Code

 

 

 

******************************

思路积累:

x^2的转化,

trie树的应用,

比较大小只需考虑每一位的贡献

 

posted @ 2019-09-19 12:07  Wwb_star  阅读(141)  评论(0编辑  收藏  举报