1. 程式人生 > 其它 >Noip模擬70 2021.10.6

Noip模擬70 2021.10.6

T1 暴雨 T2 AVL樹 T3 挖掘機 T4 遊戲

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