1. 程式人生 > 其它 >Noip模擬76 2021.10.14

Noip模擬76 2021.10.14

T1 洛希極限 T2 特立獨行的圖 T3 玩遊戲 T4 駱駝

T1 洛希極限

上來一道大資料結構或者單調佇列優化$dp$

真就沒分析出來正解複雜度

正解複雜度$O(q+nm)$,但是據說我的複雜度是假的

考慮一個點轉移最優情況是從它上面的一個反$L$形轉移過來

然後維護一個冰茶姬,處理出$le,dw$陣列就可以單調佇列優化$dp$了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<iostream>
  4 #include<algorithm>
  5 #define int long long
  6 using namespace std;
7 namespace AE86{ 8 inline int read(){ 9 int x=0,f=1;char ch=getchar(); 10 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 11 while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f; 12 }inline void write(int
x,char opt='\n'){ 13 char ch[20];int len=0;if(x<0)x=~x+1,putchar('-'); 14 do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x); 15 for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);} 16 }using namespace AE86; 17 18 const int NN=2005,mod=1e9+7,inf=0x7fffffff
; 19 int T,n,m,q; 20 struct Ma{int r1,c1,r2,c2;}a[500005]; 21 22 int f[NN][NN],g[NN][NN]; 23 int le[NN][NN],dw[NN][NN]; 24 int nxt[NN][NN]; 25 26 struct Queue{ 27 #define hang 1 28 #define lie 0 29 int q[NN],h,t,bin,pos; bool opt; 30 inline void calc_h(){ 31 if(h==t) return bin=0,void(); 32 if(opt==hang){ 33 if(f[q[h]][pos]==f[q[h+1]][pos]) bin=(bin-g[q[h]][pos]+mod)%mod; 34 else{ 35 bin=0; int i=h+1; 36 while(f[q[i]][pos]==f[q[h+1]][pos]&&i<=t) bin=(bin+g[q[i]][pos])%mod,++i; 37 } 38 }else{ 39 if(f[pos][q[h]]==f[pos][q[h+1]]) bin=(bin-g[pos][q[h]]+mod)%mod; 40 else{ 41 bin=0; int i=h+1; 42 while(f[pos][q[i]]==f[pos][q[h+1]]&&i<=t) bin=(bin+g[pos][q[i]])%mod,++i; 43 } 44 } 45 } 46 inline void calc_t(int val){ 47 if(opt==hang) 48 bin=(bin+g[q[t]][pos]*(f[q[t]][pos]==f[q[h]][pos])*val+mod)%mod; 49 else 50 bin=(bin+g[pos][q[t]]*(f[pos][q[t]]==f[pos][q[h]])*val+mod)%mod; 51 } 52 inline void clear(){h=1; t=0; bin=0;} inline bool empty(){return h>t;} 53 inline int front(){return h>t?0:q[h];} inline int back(){return h>t?0:q[t];} inline int sum(){return bin;} 54 inline void pop_front(){calc_h();++h;} inline void pop_back(){calc_t(-1);--t;} 55 inline void push_back(int v){q[++t]=v;calc_t(1);} 56 }r[NN],c[NN]; 57 58 int ans1,ans2; 59 inline int gx(int x,int y){return nxt[x][y]==x?x:nxt[x][y]=gx(nxt[x][y],y);} 60 inline int gy(int x,int y){return nxt[x][y]==y?y:nxt[x][y]=gy(x,nxt[x][y]);} 61 62 inline void prework(){ 63 ans1=ans2=0; 64 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[i][j]=g[i][j]=0,le[i][j]=dw[i][j]=inf; 65 for(int i=1;i<=n;i++) r[i].clear(),f[i][1]=g[i][1]=1; 66 for(int i=1;i<=m;i++) c[i].clear(),f[1][i]=g[1][i]=1; 67 sort(a+1,a+q+1,[](Ma a,Ma b)->bool{return a.r1<b.r1;}); 68 for(int i=1;i<=n+1;i++) for(int j=1;j<=m+1;j++) nxt[i][j]=i; 69 for(int i=1;i<=q;i++) 70 for(int j=a[i].c1+1;j<=a[i].c2;j++) 71 for(int k=gx(a[i].r1+1,j);k<=a[i].r2;k=gx(k+1,j)) 72 le[k][j]=a[i].r1,nxt[k][j]=gx(k+1,j); 73 sort(a+1,a+q+1,[](Ma a,Ma b)->bool{return a.c1<b.c1;}); 74 for(int i=1;i<=n+1;i++) for(int j=1;j<=m+1;j++) nxt[i][j]=j; 75 for(int i=1;i<=q;i++) 76 for(int j=a[i].r1+1;j<=a[i].r2;j++) 77 for(int k=gy(j,a[i].c1+1);k<=a[i].c2;k=gy(j,k+1)) 78 dw[j][k]=a[i].c1,nxt[j][k]=gy(j,k+1); 79 } 80 81 namespace WSN{ 82 inline short main(){ 83 freopen("roche.in","r",stdin); freopen("roche.out","w",stdout); 84 T=read(); for(int i=1;i<NN;i++) r[i].opt=lie,c[i].opt=hang,r[i].pos=c[i].pos=i; 85 while(T--){ 86 n=read();m=read();q=read(); 87 for(int i=1;i<=q;i++) a[i].r1=read(),a[i].c1=read(),a[i].r2=read(),a[i].c2=read(); 88 prework(); 89 for(int i=2;i<=n;i++) for(int j=2;j<=m;j++){ 90 while(!r[i-1].empty()&&f[i-1][r[i-1].back()]<f[i-1][j-1]) r[i-1].pop_back(); 91 r[i-1].push_back(j-1); 92 while(!r[i-1].empty()&&r[i-1].front()<dw[i][j]) r[i-1].pop_front(); 93 f[i][j]=f[i-1][r[i-1].front()]+1; g[i][j]=max(1ll,r[i-1].sum()); 94 95 while(!c[j-1].empty()&&f[c[j-1].back()][j-1]<f[i-2][j-1]) c[j-1].pop_back(); 96 c[j-1].push_back(i-2); 97 while(!c[j-1].empty()&&c[j-1].front()<le[i][j]) c[j-1].pop_front(); 98 if(f[i][j]==f[c[j-1].front()][j-1]+1) g[i][j]=(g[i][j]+c[j-1].sum())%mod; 99 else if(f[i][j]<f[c[j-1].front()][j-1]+1) f[i][j]=f[c[j-1].front()][j-1]+1,g[i][j]=max(1ll,c[j-1].sum()); 100 } 101 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) ans1=max(ans1,f[i][j]); 102 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[i][j]==ans1) ans2=(ans2+g[i][j])%mod; 103 write(ans1,' '); write(ans2); 104 } 105 return 0; 106 } 107 } 108 signed main(){return WSN::main();}
View Code

T2 特立獨行的圖

咕咕咕,沒學過差分約束,正在學習

T3 玩遊戲

又要寫流水賬了。。。。

畢竟考試的時候狂肝$3$小時,不寫一寫也對不住自己

但還是以後不要剛題了,會出事的。。。。會$\huge{爆蛋蛋!!}$

發現給的樣例都不能手玩,於是就自己在紙上玩了$n=1,2,3,4$的樣例,

剛開始發現像$LIS$,後來打完發現$n=4$的唯一一組資料不對$1,3,4,2$

然後就蒙了,然後就開始槓了,然後就死了。就是沒發現他是個單調棧的操作。。。

先說說怎麼玩,比如$2,3,1$這種情況是剩下來一個人的

第二個人不知道自己拿$3$,但是他發現前面是個$2$,自己後面是有$1,3$兩個數字的

那麼他肯定是想要保底留下一個$2$,不至於被後面的$1$換走

按照這個思路手玩發現單調找然後出來調和級數是可以的

但是打表他更快,但不推薦使用

題解上的證明始終覺得過於麻煩了,而且不知道有沒有問題,看到那個關鍵時刻就轉不過來彎了

所以口胡一下自己的理解:

題目裡說每個人絕頂聰明,那麼他們一定不會去幹一些可能虧本的買賣

如果當他前面的出現的數字的最大值大於後面出現的(包括自己)數字的最小值時,

他就會覺得有一定風險自己會被後面的那個最小值換掉,因為不難發現這個前面數字的最大值是單調遞減的,

他如果不換,他就有可能會死,就是這樣,那麼他肯定不會去冒風險去賭自己會不會更好,而是選擇保底

這樣的話就有一個結論,設$maxP$為出現數字的集合裡的最大值,$minR$為未出現數字集合的最小值

當$maxP<minR$時,選擇操作$1$,否則操作$2$

設$suf_i$表示從$i$開始的字尾中的元素最小值

那麼進一步推導(或者說發現)得出執行操作一的條件實際上是$[a_i=suf_i]$

所以題目轉化為求所有排列中$\sum[a_i=suf_i]$,然後可以推出調和級數

然後用我們看不懂的求導式子化簡出一種$S_k(n)$的求解式。

和直接給出一種想不到的答案式,可以用歸納法證明(聽說)

然後題解說啥我幹啥

 1 #include<cmath>
 2 #include<algorithm>
 3 #include<iostream>
 4 #define int long long
 5 typedef long double D;
 6 using namespace std;
 7 const D r=0.57721566490153286060651209;
 8 int k,n;
 9 inline D H(int n){return log(n)+r+1.0/(2.0*n);}
10 double S[51][1000005];
11 D h[51];
12 D getans(int k,int n){
13     if(n<=1e6){
14         for(int i=1;i<=n;i++) S[0][i]=S[0][i-1]+1.0/i;
15         for(int i=1;i<=k;i++){
16             double res=0.0;
17             for(int j=1;j<=n;j++){
18                 res+=S[i-1][j];
19                 S[i][j]=res;
20             }
21         }
22         return S[k][n];
23     }
24     if(n>1e6 && k==0) return log(n)+r+1.0/(2.0*n);
25     for(int i=1;i<=k;i++) h[i]=h[i-1]+1.0/i;
26     D ans=(H(n)-h[k]);
27     for(int i=k;i;i--) ans=ans*(1.0*n)/(1.0*i);
28     return ans;
29 }
30 namespace WSN{
31     inline short main(){
32         freopen("game.in","r",stdin);
33         freopen("game.out","w",stdout);
34         cout.unsetf(ios::fixed);
35         cout.setf(ios::scientific);
36         cout.precision(9);
37         cin>>k>>n;
38         cout<<getans(k,n)<<endl;
39         return 0;
40     }
41 }
42 signed main(){return WSN::main();}
View Code

T4 駱駝

大模擬構造題,沒啥好說的,

暴力建矩陣,腦洞造方案,切題有快感,給題解點贊

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 int n,m;
  5 int g[8][6][6]={
  6     {
  7         {0,0,0,0,0,0},
  8         {0,0,0,0,0,0},
  9         {0,0,0,0,0,0},
 10         {0,0,0,0,0,0},
 11         {0,0,0,0,0,0},
 12         {0,0,0,0,0,0},
 13     },
 14     {
 15         {0, 0, 0, 0, 0, 0},
 16         {0, 2, 9, 6, 3,10},
 17         {0,16,21,24,13,18},
 18         {0, 7, 4, 1, 8, 5},
 19         {0,23,12,17,22,11},
 20         {0,15,20,25,14,19},
 21     },//從上往下 1
 22     {
 23         {0, 0, 0, 0, 0, 0},
 24         {0, 2,18,25, 3,17},
 25         {0,23,12,15,20,11},
 26         {0, 7, 4, 1, 8, 5},
 27         {0,14,19,24,13,16},
 28         {0,22, 9, 6,21,10},
 29     },//從下往上 2
 30     {
 31         {0, 0, 0, 0, 0, 0},
 32         {0, 2,12,15, 3,11},
 33         {0, 7,20,23, 8,17},
 34         {0,14, 4, 1,13,25},
 35         {0,22, 9,16,21,10},
 36         {0, 6,19,24, 5,18},
 37     },//從左往右 3
 38     {
 39         {0, 0, 0, 0, 0, 0},
 40         {0, 2,15, 6, 3,14},
 41         {0, 8,20,23,11,19},
 42         {0,25, 4, 1,16, 5},
 43         {0,22,12, 7,21,13},
 44         {0, 9,17,24,10,18},
 45     },//從右往左 4
 46     {
 47         {0, 0, 0, 0, 0, 0},
 48         {0,22, 3, 9,23, 2},
 49         {0,16,25,20,17, 7},
 50         {0,10,13, 1, 4,12},
 51         {0,21,18, 8,24,19},
 52         {0,15, 5,11,14, 6},
 53     },//奇數右下角 5
 54     {
 55         {0, 0, 0, 0, 0, 0},
 56         {0, 1,19, 7, 4,20},
 57         {0,14,11,22,17,12},
 58         {0, 8, 5, 0, 9, 6},
 59         {0, 2,18,13, 3,21},
 60         {0,15,10,23,16, 0},
 61     },//奇數起點 6
 62     {
 63         {0, 0, 0, 0, 0, 0},
 64         {0, 1, 6,13,16, 5},
 65         {0,11,18, 3, 8,19},
 66         {0,23,15, 0,22,14},
 67         {0, 2, 7,12,17, 4},
 68         {0,10,21,24, 9,20},
 69     }
 70     //偶數起點 7
 71 };
 72 const int NN=1005;
 73 int ans[NN][NN],sum;
 74 inline void update(int x,int y,int id,int sum){
 75     for(int i=x;i<=x+4;i++)
 76         for(int j=y;j<=y+4;j++)
 77             ans[i][j]=g[id][i-x+1][j-y+1]+sum;
 78 }
 79 inline void print(){
 80     for(int i=1;i<=n;i++){
 81         for(int j=1;j<=n;j++){
 82             printf("%3d ",ans[i][j]);
 83         } puts("");
 84     }
 85 }
 86 inline void even(){
 87     update(1,1,7,0); sum=24;
 88     for(int i=2;i<m;i++) update(1+5*(i-1),1,1,sum),sum+=25;
 89     for(int i=1;i<m;i++) update(1+5*(m-1),1+5*(i-1),3,sum),sum+=25;
 90     update(1+5*(m-1),1+5*(m-1),2,sum); sum+=25;
 91     for(int i=m-1;i>=1;i--){
 92         if(i&1){
 93             for(int j=m;j>1;j--){
 94                 if(i==1&&j==2) update(1+5*(i-1),1+5*(j-1),4,sum);
 95                 else if(j==2) update(1+5*(i-1),1+5*(j-1),2,sum);
 96                 else update(1+5*(i-1),1+5*(j-1),4,sum);
 97                 sum+=25;
 98             }
 99         }else{
100             for(int j=2;j<=m;j++){
101                 if(j==m) update(1+5*(i-1),1+5*(j-1),2,sum);
102                 else update(1+5*(i-1),1+5*(j-1),3,sum);
103                 sum+=25;
104             }
105         }
106     }
107     ans[3][3]=n*n;
108     print();
109 }
110 inline void odd(){
111     update(1,1,6,0); sum=23;
112     for(int i=2;i<m;i++) update(1+5*(i-1),1,1,sum),sum+=25;
113     for(int i=1;i<m;i++) update(1+5*(m-1),1+5*(i-1),3,sum),sum+=25;
114     update(1+5*(m-1),1+5*(m-1),2,sum); sum+=25;
115     for(int i=m-1;i>2;i--){
116         if(i&1){
117             for(int j=2;j<=m;j++){
118                 if(j==m) update(1+5*(i-1),1+5*(j-1),2,sum);
119                 else update(1+5*(i-1),1+5*(j-1),3,sum);
120                 sum+=25;
121             }
122         }else{
123             for(int j=m;j>1;j--){
124                 if(j==2) update(1+5*(i-1),1+5*(j-1),2,sum);
125                 else update(1+5*(i-1),1+5*(j-1),4,sum);
126                 sum+=25;
127             }
128         }
129     }
130     for(int i=m;i>2;i--){
131         if(i&1){
132             update(6,1+5*(i-1),2,sum);sum+=25;
133             update(1,1+5*(i-1),4,sum);sum+=25;
134         }else{
135             update(1,1+5*(i-1),1,sum);sum+=25;
136             update(6,1+5*(i-1),4,sum);sum+=25;
137         }
138     }
139     update(1,6,1,sum); sum+=25;
140     update(6,6,5,sum); sum+=25;
141     ans[3][3]=n*n; ans[5][5]=n*n-1;
142     print();
143 }
144 namespace WSN{
145     inline short main(){
146         freopen("camel.in","r",stdin);
147         freopen("camel.out","w",stdout);
148         scanf("%d",&n); m=n/5;
149         if(n==5){
150             puts("1 11 18 4 10");
151             puts("16 22 8 13 23");
152             puts("19 5 25 20 6");
153             puts("2 12 17 3 9");
154             puts("15 21 7 14 24");
155             return 0;
156         }
157         if(n&1) return odd(),0;
158         even();
159         return 0;
160     }
161 }
162 signed main(){return WSN::main();}
View Code