17-09-20模拟赛

T1:对于加法用前缀和sumi表示第i个数,对于修改,直接将sumi的值改为修改后的值。

如果查询的区间[l,r]内有修改操作,那么就输出sumr,否则输出sumr-suml-1.

注意需按题目要求解码,同时用long long存储部分数据。

Code:

 1 #include<iostream>
 2 #include<cstdio>
 3 #define MN 10000005
 4 #define ll long long
 5 #define mod 998244353
 6 using namespace std;
 7 unsigned int seed,a[MN];
 8 int n,m,l[MN],r[MN],ans=0,sum[MN],pos[MN],pwr=1;
 9 bool type[MN];
10 unsigned int GetNext(){
11     seed^=(seed<<7);seed^=(seed>>8);seed^=(seed<<13);
12     return seed;
13 }
14 int main()
15 {
16     scanf("%d%d%u",&n,&m,&seed);sum[0]=pos[0]=0;
17     for (int i=1;i<=n;++i) type[i]=GetNext()%2,a[i]=GetNext();
18     for (int i=1;i<=n;++i){
19         if (!type[i]) sum[i]=(1ll*sum[i-1]+(1ll*a[i])%mod)%mod,pos[i]=pos[i-1];
20         else pos[i]=i,sum[i]=(1ll*a[i])%mod;
21     }for (int i=1;i<=m;++i){
22         l[i]=GetNext()%n+1,r[i]=GetNext()%n+1;int tmp;
23         if(l[i]>r[i]) tmp=l[i],l[i]=r[i],r[i]=tmp;
24         ll res=0ll;pwr=(233ll*pwr)%mod;
25         res=(l[i]<=pos[r[i]]?sum[r[i]]:sum[r[i]]-sum[l[i]-1]);
26         if (res<0) res+=mod;ans=(1ll*ans+(1ll*pwr*res)%mod)%mod;
27     }cout<<ans;return 0;
28 }

T2:可知若两个字符串的最小表示相同,那么它们循环同构。

对每个字符串求其最小表示,将其最小表示插入trie树中。时间复杂度O(nm).

亦可用字符串hash通过此题。

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MN 1000005
 5 using namespace std;
 6 inline int in(){
 7     int x=0;bool f=0; char c;
 8     for (;(c=getchar())<'0'||c>'9';f=c=='-');
 9     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
10     return f?-x:x;
11 }
12 char s[MN<<1];
13 int f[MN][26],v[MN],n,m,pos,u,cnt=0;
14 long long ans=0ll;
15 inline int expr(){
16     int i=0,j=1;while (i<m&&j<m){
17         int k=0;
18         while (s[i+k]==s[j+k]&&k<m-1) ++k;
19         if (s[i+k]<s[j+k]) j+=k+1;else i+=k+1;
20         if (i==j) ++j;
21     }return i<j?i:j;
22 }
23 int main()
24 {
25     n=in();m=in();for (int i=1;i<=n;++i){
26         scanf("%s",s);for (int j=0;j<=m;++j) s[j+m]=s[j];
27         pos=expr();u=1;
28         for (int i=0;i<m;++i){
29             if (!f[u][s[pos+i]-'a']) f[u][s[pos+i]-'a']=(++cnt);
30             u=f[u][s[pos+i]-'a'];
31         }ans+=1ll*v[u];++v[u];
32     }printf("%lld",ans);return 0;
33 }

T3:树形dp.

易知答案为叶子节点中的一个值。从大到小考虑每个数字,将大于或等于该数字k的数字认为是合法的。

f[i]表示i的能量值v[i]合法时最少需要填充的数字个数。

对于叶子节点i不能被交换时,v[i]合法,则f[i]=0,否则f[i]=inf.对于i可以被交换时,f[i]=1.

对于非叶结点i,v[i]等于i的三个儿子中f值较小的两个儿子的f[i]值之和。判断f[1]是否超过m即可。

易知k值越小时f值越小,合法的数字越多,具有单调性。考虑二分答案。时间复杂度O(n log n).

Code:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define MN 1000005
 5 #define inf 1000000000
 6 using namespace std;
 7 inline int in(){
 8     int x=0;bool f=0; char c;
 9     for (;(c=getchar())<'0'||c>'9';f=c=='-');
10     for (x=c-'0';(c=getchar())>='0'&&c<='9';x=(x<<3)+(x<<1)+c-'0');
11     return f?-x:x;
12 }
13 int f[MN][3],val[MN],st[MN],n,m,x,cnt=0,ans;
14 bool tr[MN];
15 inline int dp(int u,int v){
16     if (f[u][0]==-1) return tr[u]?1:(val[u]>=v?0:inf);
17     else {
18         int sum[3];memset(sum,0,sizeof(sum));
19         for (int i=0;i<3;++i) sum[i]=dp(f[u][i],v);
20         sort(sum,sum+3);return min(n+1,sum[0]+sum[1]);
21     }
22 }
23 int main()
24 {
25     n=in();m=in();for (int i=1;i<=n;++i){
26         f[i][0]=in();if (f[i][0]==-1) val[i]=in();
27         else f[i][1]=in(),f[i][2]=in();
28     }for (int i=1;i<=m;++i){
29         x=in();tr[x]=1;st[++cnt]=val[x];
30     }sort(st+1,st+cnt+1);int l=1,r=inf;
31     while (l<=r){
32         int mid=(l+r)>>1;
33         if (dp(1,mid)<=cnt-(lower_bound(st+1,st+cnt+1,mid)-st)+1) 
34         ans=mid,l=mid+1;else r=mid-1;
35     }printf("%d",ans);return 0;
36 }
posted on 2017-09-26 17:36  whz2002  阅读(120)  评论(0编辑  收藏  举报