Noip模拟70 2021.10.6

时间:2021-10-07
本文章向大家介绍Noip模拟70 2021.10.6,主要包括Noip模拟70 2021.10.6使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

T1 暴雨

放在第一道的神仙题,不同的做法,吊人有的都在用线段树维护$set$预处理

我是直接$dp$的,可能代码的复杂度比那种的稍微小一点

设$f[i][j][p][0/1]$表示考虑了前$i$列,里面的最大值高度是$j$,

并且后面还至少存在高度为$j$的土块,在前$i$列挖平了$p$个土块,积水的体积是奇数或者偶数的方案数

采用刷表更新$dp$值的方法,更新$f[i][j][k][u]$的所有可能到达的状态

可能有人问数组怎么开,因为$k \leq 26$所以最大值的哪一维只记录前$k+1$大即可

适当的给原数组离散化。

记录几个值

$val[i][j]$表示前$i$列第$j$大的土块的高度,

$cnt[i]$表示前$i$列有几个可以转移的前$j$大值(记录可转移的状态个数)

然后考虑$dp$,用$i$更新$i+1$

考虑两种情况,

1.$val[i][j] \geq a[i+1]$

$f[i+1][J][k][0/1]+=f[i][j][k][0/1]$

$f[i+1][J][k+1][0/1]+=f[i][j][k][0/1]$

2.$val[i][j] \leq a[i+1]$

$f[i+1][a_{i+1}][k][0/1]+=f[i][j][k][0/1]$

$f[i+1][J][k+1][0/1]+=f[i][j][k][0/1]$

直接做转移即可,然后因为$dp$转移的时候有一个限制,就是保证后面至少有一个高度为$j$的土块

所以为了让转移合法,我们从前往后,从后往前分别转移一次

然后考虑对$dp$值合并合并的时候保证$g,f$数组满足转移时候的关系即可

写代码的时候注意不要往超越边界的地方转移,卡一下边界即可

 1 #include<bits/stdc++.h>
 2 #define sit multiset<int>::iterator
 3 using namespace std;
 4 namespace AE86{
 5     #define out(x) cout<<#x<<":"<<x<<endl
 6     #define fuck cout<<"fuck"<<endl
 7     inline int read(){
 8         int x=0,f=1;char ch=getchar();
 9         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
10         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
11     }inline void write(int x,char opt='\n'){
12         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
13         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
14         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
15 }using namespace AE86;
16 const int NN=25010,mod=1e9+7;
17 int n,K,h[NN],id[NN],ans;
18 struct DP{
19     int a[NN],f[NN][26][26][2],val[NN][26],cnt[NN];
20     multiset<int> S;unordered_map<int,int> mp[NN];
21     inline void calc(){
22         S.insert(0);
23         for(int i=1;i<=n;i++){
24             S.insert(a[i]); sit it=S.end();
25             for(int j=1;j<=K+1;j++){
26                 if(it==S.begin()) break; --it;
27                 val[i][mp[i][*it]=++cnt[i]]=*it;
28             }
29         }
30         f[0][1][0][0]=1; val[0][cnt[0]=1]=0;
31         for(int i=0;i<n;i++) for(int j=1;j<=cnt[i];j++) for(int k=0;k<=K;k++)
32             for(int u=0;u<=1;u++) if(f[i][j][k][u]){
33                 if(val[i][j]>=a[i+1]){
34                     int J=mp[i+1][val[i][j]],sta=u^(val[i][j]-a[i+1]&1);
35                     f[i+1][J][k][sta]=(f[i+1][J][k][sta]+f[i][j][k][u])%mod;
36                     sta=u^(val[i][j]&1);
37                     if(k+1<=K) f[i+1][J][k+1][sta]=(f[i+1][J][k+1][sta]+f[i][j][k][u])%mod;
38                 }else{
39                     int J=mp[i+1][a[i+1]],sta=u^(val[i][j]&1);
40                     f[i+1][J][k][u]=(f[i+1][J][k][u]+f[i][j][k][u])%mod;
41                     J=mp[i+1][val[i][j]];
42                     if(k+1<=K) f[i+1][J][k+1][sta]=(f[i+1][J][k+1][sta]+f[i][j][k][u])%mod;
43                 }
44         }
45     }
46 }F,G;
47 namespace WSN{
48     inline short main(){
49         freopen("rain.in","r",stdin);
50         freopen("rain.out","w",stdout);
51         n=read(); K=read(); for(int i=1;i<=n;i++) h[i]=read(),F.a[i]=G.a[n-i+1]=h[i],id[i]=i;
52         F.calc(); G.calc();
53         sort(id+1,id+n+1,[](int x,int y)->bool{return h[x]>h[y];});
54         for(int i=1;i<=n;i++){
55             if(h[id[i]]<h[id[K+1]]) break;
56             int now=id[i],val=h[now];
57             for(int j=F.cnt[now-1];j;j--){
58                 if(F.val[now-1][j]>val) break;
59                 for(int k=G.cnt[n-now];k;k--){
60                     if(G.val[n-now][k]>=val) break;
61                     for(int u=0;u<=K;u++){
62                         ans=(ans+1ll*F.f[now-1][j][u][0]*G.f[n-now][k][K-u][0]%mod)%mod;
63                         ans=(ans+1ll*F.f[now-1][j][u][1]*G.f[n-now][k][K-u][1]%mod)%mod;
64                     }
65                 }
66             }
67         } write(ans%mod);
68         return 0;
69     }
70 }
71 signed main(){return WSN::main();}
View Code

T2 AVL树

不知道有没有什么简便的暴力

反正我打了$98$行才拿到了$20$分

当时就知道这一场要崩掉了,花了将近一个小时调暴力(?)

早知道去打别的题了,比如$T4$的六十分感觉貌似不难想,就是可能是调有点费劲

然后不会,就咕咕咕了

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     #define out(x) cout<<"x="<<x<<endl
 6     #define fuck cout<<"fuck"<<endl
 7     inline int read(){
 8         int x=0,f=1;char ch=getchar();
 9         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
10         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
11     }inline void write(int x,char opt='\n'){
12         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
13         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
14         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
15 }using namespace AE86;
16 const int NN=5e5+5;
17 int n,k,fa[NN],son[NN][2],root,dep[NN],mdp[NN];
18 bool vis[NN];
19 inline void getdep(int f,int x){
20     if(son[x][0]){
21         dep[son[x][0]]=dep[x]+1;
22         getdep(x,son[x][0]);
23     }
24     if(son[x][1]){
25         dep[son[x][1]]=dep[x]+1;
26         getdep(x,son[x][1]);
27     }
28 }
29 inline void dfs(int f,int x){
30     if(!vis[x]) return;
31     mdp[x]=dep[x];
32     if(son[x][0]){
33         dfs(x,son[x][0]);
34         mdp[x]=max(mdp[x],mdp[son[x][0]]);
35     }
36     if(son[x][1]){
37         dfs(x,son[x][1]);
38         mdp[x]=max(mdp[x],mdp[son[x][1]]);
39     }
40 }
41 vector<int> pre;
42 inline void bian(int x){
43     if(son[x][0]&&vis[son[x][0]]) bian(son[x][0]);
44     pre.push_back(x);
45     if(son[x][1]&&vis[son[x][1]]) bian(son[x][1]);
46 }
47 int ans[NN],sta;
48 namespace WSN{
49     inline short main(){
50         freopen("avl.in","r",stdin);
51         freopen("avl.out","w",stdout);
52         n=read(); k=read(); memset(ans,0x3f,sizeof(ans));
53         for(int i=1,x;i<=n;i++){
54             x=read(); fa[i]=x; son[x][i>x]=i;
55             if(x==-1) root=i;
56         }
57         if(k==1){
58             for(int i=1;i<=n;i++) printf(fa[i]!=-1?"0":"1");
59             return puts(""),0;
60         }
61         getdep(-1,root);
62         for(int i=1;i<(1<<n);++i) if((i&(1<<root-1))&&__builtin_popcount(i)==k){
63             for(int i=1;i<=n;++i) mdp[i]=0;
64             for(int j=1;j<=n;++j) if(i&(1<<j-1)) vis[j]=1;
65             dfs(-1,root); bool flag=0;
66             for(int j=1;j<=n;++j){
67                 if(vis[j]&&(vis[son[j][0]]||vis[son[j][1]])){
68                     int a=mdp[son[j][0]]-dep[son[j][0]];
69                     int b=mdp[son[j][1]]-dep[son[j][1]];
70                     if(!vis[son[j][0]]) a=-1;
71                     if(!vis[son[j][1]]) b=-1;
72                     if(abs(a-b)>1){flag=1;break;}
73                 }
74             }
75             if(!flag){
76                 pre.clear(); bian(root);
77                 if(pre.size()==k){
78                     for(int j=0;j<pre.size();++j){
79                         if(ans[j+1]>pre[j]){
80                             for(int j=0;j<pre.size();++j) ans[j+1]=pre[j];
81                             sta=i; break;
82                         }
83                         if(ans[j+1]<pre[j]) break;
84                     }
85                 }
86             }
87             for(int j=1;j<=n;++j) if(i&(1<<j-1)) vis[j]=0;
88         }
89         for(int i=1;i<(1<<n);++i) if(sta==i){
90             for(int j=1;j<=n;++j)
91                 if(i&(1<<j-1)) printf("1");
92                 else printf("0"); puts("");
93             break;
94         }
95         return 0;
96     }
97 }
98 signed main(){return WSN::main();}
暴力辛酸泪

T3 挖掘机

文件名叫$blueshit$就非常妙

自己的$OJ$评测姬比较快,有的拿分块写的

但是正解好像是倍增

看得到行数比较小,而且每一行不联系,所以直接一行一行搞

然后发现找到一个在$[l,r]$区间内的$X$就可以消掉连续的$k$个,这样一定最优

那么我们以$k$为一段,倍增去跳这个段数,然后你选择从$r$忘前跳和从$l$往后跳都可以,就是往后跳的时候边界的处理比较麻烦,建议往前跳

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 namespace AE86{
 4     #define out(x) cout<<"x="<<x<<endl
 5     #define fuck cout<<"fuck"<<endl
 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<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
10     }inline void write(int x,char opt='\n'){
11         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
12         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
13         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
14 }using namespace AE86;
15 const int NN=1e5+5;
16 int h,w,k,q,d,l,r,a[13][NN],sum[13][NN],b[13][NN],ans;
17 int bz[13][NN][18];
18 char ch[NN];
19 namespace WSN{
20     inline short main(){
21         freopen("blueshit.in","r",stdin);
22         freopen("blueshit.out","w",stdout);
23         h=read();w=read();k=read();q=read();
24         for(int i=1;i<=h;++i){ scanf("%s",ch+1); bz[i][w+1][0]=w+1;
25             for(int j=w;j;--j) bz[i][j][0]=ch[j]=='X'?j:bz[i][j+1][0];
26         }
27         for(int i=1;i<=h;++i) for(int j=w+1;j;--j) for(int u=1;u<=17;++u)
28             bz[i][j][u]=bz[i][min(bz[i][j][u-1]+k,w+1)][u-1];
29         while(q--){
30             d=read();l=read();r=read();ans=0;
31             for(int i=1;i<=d;++i){ int pos=l;
32                 for(int j=17;~j;--j) if(bz[i][pos][j]<=r)
33                     ans+=1<<j,pos=min(bz[i][pos][j]+k,w+1);
34             }
35             write(ans);
36         }
37         return 0;
38     }
39 }
40 signed main(){return WSN::main();}
向后跳
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 namespace AE86{
 4     #define out(x) cout<<"x="<<x<<endl
 5     #define fuck cout<<"fuck"<<endl
 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<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
10     }inline void write(int x,char opt='\n'){
11         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
12         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
13         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
14 }using namespace AE86;
15 const int NN=1e5+5;
16 int h,w,k,q,d,l,r,a[13][NN],sum[13][NN],b[13][NN],ans;
17 int bz[13][NN][18];
18 char ch[NN];
19 namespace WSN{
20     inline short main(){
21         freopen("blueshit.in","r",stdin);
22         freopen("blueshit.out","w",stdout);
23         h=read();w=read();k=read();q=read();
24         for(int i=1;i<=h;++i){ scanf("%s",ch+1);
25             for(int j=1;j<=w;++j) bz[i][j][0]=ch[j]=='X'?j:bz[i][j-1][0];
26         }
27         for(int i=1;i<=h;i++) for(int j=1;j<=w;j++) for(int u=1;u<=17;u++)
28             bz[i][j][u]=bz[i][max(bz[i][j][u-1]-k,0)][u-1];
29         while(q--){
30             d=read();l=read();r=read();ans=0;
31             for(int i=1;i<=d;i++){ int pos=r;
32                 for(int j=17;~j;j--) if(bz[i][pos][j]>=l)
33                     ans+=1<<j,pos=max(bz[i][pos][j]-k,0);
34             } write(ans);
35         }
36         return 0;
37     }
38 }
39 signed main(){return WSN::main();}
向前跳

T4 游戏

$n^2$的暴力考后打了出来

枚举两个字符串的初始匹配点,然后二分找到最长的匹配长度,更新平局的树状数组,然后从最长匹配点后面比较字典序

然后更新两者谁胜谁负的树状数组,最后直接查询即可

 1 #include<stdio.h>
 2 #include<cstring>
 3 #define int long long
 4 typedef unsigned long long ULL;
 5 const ULL base=131;
 6 const int NN=8010;
 7 int n,m,k;
 8 char A[NN],B[NN];
 9 ULL a[NN],b[NN],pw[NN];
10 struct BIT{
11     int tr[NN];
12     inline void update(int x,int v){
13         ++x;while(x<NN) tr[x]+=v,x+=(x&(-x));
14     }
15     inline int query(int x,int ans=0){
16         ++x;while(x) ans+=tr[x],x-=(x&(-x));
17         return ans;
18     }
19 }c1,c2,c3;
20 
21 inline int _min_(int a,int b){return a<b?a:b;}
22 inline ULL get(int l,int r,ULL *a){
23     return a[r]-a[l-1]*pw[r-l+1];
24 }
25 inline int gcd(int a,int b){
26     return b?gcd(b,a%b):a;
27 }
28 inline bool check(int p1,int p2,int len){
29     if(p1+len-1>n||p2+len-1>m) return 0;
30     return get(p1,p1+len-1,a)==get(p2,p2+len-1,b);
31 }
32 int st1,st2,ed,l,r,ans,mid;
33 namespace WSN{
34     inline short main(){
35         freopen("game.in","r",stdin);
36         freopen("game.out","w",stdout);
37         pw[0]=1; for(int i=1;i<NN;++i) pw[i]=pw[i-1]*base;
38         scanf("%s",A+1); scanf("%s",B+1);
39         n=strlen(A+1); m=strlen(B+1); k=_min_(n,m);
40         for(int i=1;i<=n;++i) a[i]=a[i-1]*base+(ULL)(A[i]-'a'+1);
41         for(int i=1;i<=m;++i) b[i]=b[i-1]*base+(ULL)(B[i]-'a'+1);
42         for(int i=1;i<=n;++i){
43             for(int j=1;j<=m;++j){
44                 ans=0; ed=_min_(n-i+1,m-j+1);
45                 if(A[i]==B[j]){
46                     l=0,r=ed;
47                     while(l<=r){
48                         mid=l+r>>1;
49                         if(check(i,j,mid)) l=mid+1,ans=mid;
50                         else r=mid-1;
51                     }c2.update(1,1); c2.update(ans+1,-1);
52                 }st1=i+ans,st2=j+ans;
53                 if(A[st1]<B[st2]) c1.update(ans+1,1),c1.update(ed+1,-1);
54                 else c3.update(ans+1,1),c3.update(ed+1,-1);
55             }
56         }
57         for(int a1,a2,a3,GCD,tot,b1,b2,b3,C1,C2,C3,i=1;i<=k;++i){
58             a1=c1.query(i),a2=c2.query(i),a3=c3.query(i);
59             GCD=gcd(a1,gcd(a2,a3)),tot=a1/GCD+a2/GCD+a3/GCD;
60             b1=a1/GCD,b2=a2/GCD,b3=a3/GCD;
61             C1=gcd(b1,tot),C2=gcd(b2,tot),C3=gcd(b3,tot);
62             printf("%lld/%lld %lld/%lld %lld/%lld\n",b1/C1,tot/C1,b2/C2,tot/C2,b3/C3,tot/C3);
63         }
64         return 0;
65     }
66 }
67 signed main(){return WSN::main();}
RE 60

原文地址:https://www.cnblogs.com/hzoi-wsn/p/15377209.html