• 2017/9/20模拟赛


     

     

    题解:这题重点是怎样算出询问的答案,我们发现,若l[i]与r[i]间有1操作,在1操作前的操作都没意义了,我们就用前缀和,然后求出max(l[i],last[r[i]])间的和即可(last[i]为i前第一个1操作的位置)。注意该膜的要膜,不然会挂QAQ。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #define MN 10000005
     4 #define Mod 998244353
     5 using namespace std;
     6 unsigned int seed,a[MN];
     7 int n,m,l[MN],r[MN],last[MN];
     8 long long ans=0,la,w=1,sum[MN],now;
     9 bool type[MN];
    10 unsigned int GetNext(){
    11     seed^=(seed<<7);
    12     seed^=(seed>>8);
    13     seed^=(seed<<13);
    14     return seed;
    15 }
    16 int main()
    17 {
    18     freopen("math.in","r",stdin);
    19     freopen("math.out","w",stdout);
    20     scanf("%d%d%u",&n,&m,&seed);
    21     for(int i=1;i<=n;++i) type[i]=GetNext()%2,a[i]=GetNext();
    22     for(int i=1;i<=m;++i){
    23         l[i]=GetNext()%n+1,r[i]=GetNext()%n+1;
    24         int tmp;
    25         if(l[i]>r[i]) tmp=l[i],l[i]=r[i],r[i]=tmp;
    26     }
    27     for(int i=1;i<=n;i++){
    28         if(type[i]==1) last[i]=i;
    29         else last[i]=last[i-1];
    30         sum[i]=sum[i-1]+a[i];
    31     }
    32     for(int i=1;i<=m;i++){
    33         now=sum[r[i]]-sum[max(l[i],last[r[i]])-1];
    34         w=w*233%Mod;
    35         ans=(ans+now%Mod*w%Mod)%Mod;
    36     }
    37     cout<<ans;
    38     return 0;
    39 }

     

     

    题解:可以发现,所有循环同构的字符串的最小表示法都相等,所以我们从每个字符串的最小表示法向后搜完整个字符,具体看代码吧,中间输出一下就秒理解了。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #define MN 1000005
     5 using namespace std;
     6 int n,m,val[MN],c[MN][26],cnt;
     7 char st[MN];long long ans;
     8 int getmin(char *s){
     9     int len=strlen(s);
    10     int i=0,j=1,k=0,t;
    11     while(i<m&&j<m&&k<m){
    12         t=s[(i+k)%m]-s[(j+k)%m];
    13         if(!t) k++;
    14         else{
    15             if(t>0) i+=k+1;else j+=k+1;
    16             if(i==j) j++; k=0;
    17         }
    18     }
    19     return i<j?i:j;
    20 }
    21 int main()
    22 {
    23     freopen("english.in","r",stdin);
    24     freopen("english.out","w",stdout);
    25     scanf("%d%d",&n,&m);
    26     for(int i=1;i<=n;i++){
    27         scanf("%s",st);
    28         int pos=getmin(st),x=0;
    29         for(int i=0;i<m;i++){
    30             if(!c[x][st[(pos+i)%m]-'a']) c[x][st[(pos+i)%m]-'a']=++cnt;
    31             x=c[x][st[(pos+i)%m]-'a'];
    32             //cout<<x<<" ";
    33         }//puts("");
    34         ans+=val[x]++;
    35     }
    36     cout<<ans;
    37     return 0;
    38 }

     

    题解:首先答案肯定是那 m 个数字中的一个。我们考虑从大到小考虑每个数字,合法就输出。确定要判断的数字之后,就只剩下了两种数字,分别大等于或者小于要判断的数字。这里认为大等于的数字是合法的。我们用 f[i]表示 i 的能量值大等于要判断的数字最少需要填入几个合法的数字,那么对于确定的叶子点,如果他合法,f[i]=0,否则 f[i]=INF。对于不确定的,f[i]=1然后就有了转移, f[i]就等同于它的三个儿子中比较小的两个 f 的和。最后我们只需要判断是否有足够的数字填入即可。
     复杂度 O(n^2) 总共可以获得70分。
    在此基础上二分,即可100分。

    代码如下:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<algorithm>
     4 #define MN 1000005
     5 using namespace std;
     6 inline int read(){
     7     int x=0,f=1;char ch=getchar();
     8     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
     9     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    10     return x*f;
    11 }
    12 int s[MN],n,m,c[MN][3],cnt,res,mark[MN],L[MN],mid;
    13 int Dp(int x){
    14     if(c[x][0]==-1) return mark[x]?1:(s[x]>=mid?0:1e9);
    15     else{
    16         int s1=Dp(c[x][0]),s2=Dp(c[x][1]),s3=Dp(c[x][2]);
    17         if(s1>s2) swap(s2,s1);if(s2>s3) swap(s2,s3);if(s1>s2) swap(s1,s2);
    18         return min(n+1,s1+s2);
    19     }
    20 }
    21 int main()
    22 {
    23     freopen("chemistry.in","r",stdin);
    24     freopen("chemistry.out","w",stdout);
    25     n=read(); m=read();
    26     for(int i=1;i<=n;++i) 
    27         if((c[i][0]=read())==-1) s[i]=read();
    28         else c[i][1]=read(),c[i][2]=read();
    29     for(int i=1;i<=m;++i) mark[read()]=1;
    30     for(int i=1;i<=n;++i) if(mark[i]) L[++cnt]=s[i];
    31     sort(L+1,L+cnt+1);int l=1,r=1e9;
    32     while(l<=r){
    33         mid=l+r>>1;
    34         if(Dp(1)<=cnt-(lower_bound(L+1,L+cnt+1,mid)-L)+1) res=mid,l=mid+1;
    35         else r=mid-1;
    36     }
    37     printf("%d
    ",res);
    38     return 0;
    39 }
  • 相关阅读:
    shell习题第21题:计算数字的个数
    shell习题第20题:统计文件大小
    萌新小白
    编程第一天
    萌新报道
    linux下安装php扩展pdo_oci和oci8
    安装Hadoop伪分布式踩过的坑
    zabbix安装过程
    MySQL_索引
    mysql复制
  • 原文地址:https://www.cnblogs.com/Beginner-/p/7568025.html
Copyright © 2020-2023  润新知