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\n",res);
38     return 0;
39 }

 

posted @ 2017-09-21 12:51  Beginner_llg  阅读(152)  评论(0编辑  收藏  举报