2018.8.7 Noip2018模拟测试赛(二十)

日期:

八月七号

 总分:

300分

 难度:

提高 ~ 省选  

 得分:

100分(呵呵一笑)

题目列表:

  T1:SS

  T2:Tree Game

  T3:二元运算

赛后反思:

Emmmmmm……

开局随便看,第二题发现手算样例不对……

比赛快结束时,又看了看题,才发现自己看错了……

最终,改A了……Emmmmmm……

题解:

T1:SS

特别特别玄学的一道题……

原串是一个偶串,设半个原串为S,加起来就是SS。

设S的最长公共前缀后缀为T,(用 KMP 的 next 求)

那么接下来的串为 STST,STSSTS,STSSTSTSST……

只看一半:S,ST,STS,STSST……

这不是斐波那契吗?由于斐波那增长很快,我们暴力求出在 l,r 的串,差分出答案。

CODE:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 char s[500005];
 7 long long l,r,siz[500005],sum[500005][26],ans[26];
 8 int n,lim,nxt[500005];
 9 
10 void get_next(){
11     int i=1,j=0;
12     nxt[1]=0;
13     while(i<=n){
14         if(j==0||s[i]==s[j]){
15             nxt[++i]=++j;
16         }else j=nxt[j];
17     }
18 }
19 
20 void get_ans(long long x,int f){
21     for(int i=lim;i>=0;i--)
22         if(x>=siz[i]){
23             for(int j=0;j<26;j++)
24                 ans[j]+=f*sum[i][j];
25             x-=siz[i];
26         }
27     for(int i=1;i<=x;i++)ans[s[i]-'a']+=f;
28 }
29 
30 int main(){
31     scanf("%s%lld%lld",s+1,&l,&r);
32     n=strlen(s+1)>>1;
33     get_next();
34     int t=nxt[n];
35     for(int i=1;i<=n;i++)sum[0][s[i]-'a']++;
36     for(int i=0;i<26;i++)sum[1][i]=sum[0][i];
37     for(int i=1;i<=n-t;i++)sum[1][s[i]-'a']++;
38     siz[0]=n,siz[1]=2*n-t;
39     for(int i=2;i<=100;i++){
40         for(int j=0;j<26;j++)
41             sum[i][j]=sum[i-1][j]+sum[i-2][j];
42         siz[i]=siz[i-1]+siz[i-2];
43         if(siz[i]>1e18){lim=i;break;}
44     }
45     get_ans(l-1,-1);
46     get_ans(r,1);
47     for(int i=0;i<26;i++)printf("%lld ",ans[i]);
48     return 0;
49 }

T2:Tree Game

你可以很轻易的发现一个结论,先手必须要往权值更小的点走,不然对手跟你对着干就能把你逼死。

当前子树如果有必胜的策略,那就一定有一个儿子的子树是必胜的,且权值小于它。

于是乎,dp秒杀吧!时间 $O(n^2)$

CODE:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 int tot=0,h[3005];
 7 int n,x,y,f[3005],val[3005];
 8 struct Edge{
 9     int x,next;
10 }e[6005];
11 
12 inline void add_edge(int x,int y){
13     e[++tot].x=y;
14     e[tot].next=h[x],h[x]=tot;
15 }
16 
17 void dfs(int x){
18     f[x]=0;
19     for(int i=h[x];i;i=e[i].next){
20         if(~f[e[i].x])continue;
21         dfs(e[i].x);
22         if(val[e[i].x]<val[x]&&f[e[i].x]==0)f[x]=1;
23     }
24 }
25 
26 int main(){
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++)scanf("%d",val+i);
29     for(int i=1;i<n;i++){
30         scanf("%d%d",&x,&y);
31         add_edge(x,y);
32         add_edge(y,x);
33     }
34     for(int i=1;i<=n;i++){
35         memset(f,-1,sizeof(f));
36         dfs(i);
37         if(f[i])printf("%d ",i);
38     }
39 }

T3:二元运算

CDQ分治加FFT。

如果只有第一种运算就是裸的FFT求卷积,只有第二种运算可以把B序列翻转,然后求卷积即可。

但是有 x 与 y 大小关系的限制使得我们不能直接求卷积来得出答案。

考虑分治,对于每个区间 $[l,r]$,处理出$A$中的$[l,mid]$与$B$中的$[mid+1,r]$对答案的贡献以及$A$中的$[mid+1,r]$与$B$中的$[l,mid]$对答案的贡献,这两个是有严格的 x 与 y 的大小关系的,分别使用 FFT 求卷积解决。再递归处理子区间即可。

时间复杂度$O(Tnlog^2n)$

CODE:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cmath>
  5 using namespace std;
  6  
  7 #pragma GCC optimize(3)
  8  
  9 const double PI=acos(-1);
 10 int T,n,m,q,x;
 11 int rev[400005],A[200005],B[200005];
 12 long long ans[400005];
 13 struct cmplx{
 14     double x,y;
 15     cmplx(double a=0,double b=0){x=a;y=b;}
 16     cmplx operator+(cmplx b){
 17         return cmplx(x+b.x,y+b.y);
 18     }
 19     cmplx operator+=(cmplx b){
 20         return *this=*this+b;
 21     }
 22     cmplx operator-(cmplx b){
 23         return cmplx(x-b.x,y-b.y);
 24     }
 25     cmplx operator*(cmplx b){
 26         return cmplx(x*b.x-y*b.y,x*b.y+y*b.x);
 27     }
 28     cmplx operator*=(cmplx b){
 29         return *this=*this*b;
 30     }
 31 }a[400005],b[400005];
 32 
 33 int read(){
 34     int x=0;
 35     char c;
 36     do c=getchar();
 37     while(!isdigit(c));
 38     do{
 39         x=(x<<1)+(x<<3)+(c^48);
 40         c=getchar();
 41     }while(isdigit(c));
 42     return x;
 43 }
 44  
 45 void FFT(cmplx a[],int bit,int dft){
 46     for(int i=0;i<bit;i++)
 47         if(i<rev[i])swap(a[i],a[rev[i]]);
 48     for(int i=1;i<bit;i<<=1){
 49         cmplx W(cos(PI/i),dft*sin(PI/i));
 50         for(int j=0;j<bit;j+=i<<1){
 51             cmplx w(1,0);
 52             for(int k=j;k<i+j;k++,w=w*W){
 53                 cmplx x=a[k];
 54                 cmplx y=w*a[k+i];
 55                 a[k]=x+y,a[k+i]=x-y;
 56             }
 57         }
 58     }
 59     if(dft==-1)for(int i=0;i<bit;i++)a[i].x/=bit;
 60 }
 61  
 62 void solve(int l,int r){
 63     if(l==r)return;
 64     int mid=l+r>>1,n=1;
 65     while(n<=r-l+1)n<<=1;
 66     for(int i=l;i<=mid;i++)
 67         a[i-l]=cmplx(A[i],0);
 68     for(int i=mid+1;i<=r;i++)
 69         b[i-mid-1]=cmplx(B[i],0);
 70     for(int i=mid-l+1;i<n;i++)
 71         a[i]=cmplx(0,0);
 72     for(int i=r-mid;i<n;i++)
 73         b[i]=cmplx(0,0);
 74     for(int i=0;i<n;i++)
 75         rev[i]=(rev[i>>1]>>1)|(i&1)*(n>>1);
 76     FFT(a,n,1),FFT(b,n,1);
 77     for(int i=0;i<n;i++)a[i]=a[i]*b[i];
 78     FFT(a,n,-1);
 79     for(int i=0;i<=r-l+1;i++)
 80         ans[i+l+mid+1]+=(long long)(a[i].x+0.5);
 81     solve(l,mid),solve(mid+1,r);
 82 }
 83  
 84 int main(){
 85     T=read();
 86     while(T--){
 87         memset(A,0,sizeof(A));
 88         memset(B,0,sizeof(B));
 89         memset(a,0,sizeof(a));
 90         memset(b,0,sizeof(b));
 91         memset(ans,0,sizeof(ans));
 92         int maxn=0,bit=1;
 93         n=read(),m=read(),q=read();
 94         for(int i=1;i<=n;i++){
 95             x=read();
 96             A[x]++,maxn=max(maxn,x);
 97         }
 98         for(int i=1;i<=m;i++){
 99             x=read();
100             B[x]++,maxn=max(maxn,x);
101         }
102         while(bit<=maxn<<1)bit<<=1;
103         for(int i=0;i<bit;i++)
104             rev[i]=(rev[i>>1]>>1)|(i&1)*(bit>>1);
105         for(int i=0;i<=maxn;i++)
106             b[maxn-i].x=B[i];
107         for(int i=0;i<=maxn;i++)
108             a[i].x=A[i];
109         FFT(a,bit,1),FFT(b,bit,1);
110         for(int i=0;i<bit;i++)a[i]=a[i]*b[i];
111         FFT(a,bit,-1);
112         for(int i=0;i<=maxn;i++)
113             ans[i]=(long long)(a[i+maxn].x+0.5);
114         solve(0,maxn);
115         for(int i=1;i<=q;i++){
116             x=read();
117             printf("%lld\n",ans[x]);
118         }
119     }
120 }
posted @ 2018-08-07 21:45  ezoiLZH  阅读(211)  评论(0编辑  收藏  举报