• 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
    ",ans[x]);
    118         }
    119     }
    120 }
  • 相关阅读:
    Android ContentProvider 简介
    Android Broadcaset 简介
    Android Service 简介
    XML SAX解析
    XML DOM解析
    RSS新闻阅读器
    XML PULL模型
    Android调用 Webservice报org.ksoap2.serialization.SoapPrimitive(转)
    Android调用Asp.net Web Service示例
    Eclipse编辑器基本设置
  • 原文地址:https://www.cnblogs.com/ezoiLZH/p/9439685.html
Copyright © 2020-2023  润新知