Loading

Noip模拟76 2021.10.14

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

 

posted @ 2021-10-16 10:17  雪域亡魂  阅读(111)  评论(0编辑  收藏  举报