Loading

Noip模拟61 2021.9.25

 

T1 交通

考场上想了一个$NPC$。应该吧,是要求出图里面的所有可行的不重复欧拉路

无数种做法都无法解出,时间也都耗在这个上面的,于是就考的挺惨的

以后要是觉得当前思路不可做,就试着换一换思路,千万不能在一道题上花费太多时间

正解是一个关系的判断

每一条边选还是不选都会跟另一条边产生连锁关系,那么给他们编上号建边,用并查集判断环就行

然后每个环上选择$n$个不相邻的点,总共$2^{环数}$种方案

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=2e5+5,mod=998244353;
15 inline int qmo(int a,int b,int ans=1){
16     int c=mod; while(b){
17         if(b&1) ans=1ll*ans*a%c;
18         b>>=1; a=1ll*a*a%c;
19     } return ans;
20 }
21 struct node{int u,v,id;}p[NN<<1];
22 int n,in[NN<<1][2],ot[NN<<1][2],tot,fa[NN<<1];
23 inline int getfa(int x){return fa[x]=(fa[x]==x?x:getfa(fa[x]));}
24 namespace WSN{
25     inline short main(){
26         freopen("a.in","r",stdin);
27         freopen("a.out","w",stdout);
28         n=read();
29         for(int i=1;i<=n*2;i++) fa[i]=i;
30         for(int i=1;i<=n*2;i++){
31             p[i].u=read(), p[i].v=read();
32             if(in[p[i].v][0]) in[p[i].v][1]=i; else in[p[i].v][0]=i;
33             if(ot[p[i].u][0]) ot[p[i].u][1]=i; else ot[p[i].u][0]=i;
34         }
35         // for(int i=1;i<=n;i++) cout<<in[i][0]<<" "<<in[i][1]<<endl;
36         for(int i=1;i<=n;i++){
37             int X=getfa(in[i][0]),Y=getfa(in[i][1]);
38             if(X==Y) ++tot; else fa[X]=Y;
39             X=getfa(ot[i][0]); Y=getfa(ot[i][1]);
40             if(X==Y) ++tot; else fa[X]=Y;
41         }
42         write(qmo(2,tot));
43         return 0;
44     }
45 }
46 signed main(){return WSN::main();}
View Code

 

T2 小P的单调数列

考虑出一个结论后就非常可做了,就是关于他的价值是取平均,那么分的段越少越好

我们就只比较分成两段的情况和单调上升的情况

然后按照最大权上升子序列处理就好了,写的权值线段树,常数可能会大,可以写两个树状数组

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }
10 }using namespace AE86;
11 const int NN=1e5+5;
12 int n,a[NN],dis[NN],new_n;
13 int dp1[NN],dp2[NN];
14 struct SNOWtree{
15     #define lid (id<<1)
16     #define rid (id<<1|1)
17     #define mid ((l+r)>>1)
18     int maxn[NN<<2];
19     inline void insert(int id,int l,int r,int pos,int val){
20         if(l==r){maxn[id]=max(maxn[id],val);return;}
21         if(pos<=mid) insert(lid,l,mid,pos,val);
22         else insert(rid,mid+1,r,pos,val);
23         maxn[id]=max(maxn[lid],maxn[rid]);
24     }
25     inline int query(int id,int l,int r,int ql,int qr){
26         if(ql<=l && r<=qr) return maxn[id]; int ans=0;
27         if(ql<=mid) ans=max(ans,query(lid,l,mid,ql,qr));
28         if(qr>mid) ans=max(ans,query(rid,mid+1,r,ql,qr));
29         return ans;
30     }
31 }tr;
32 namespace WSN{
33     inline short main(){
34         freopen("b.in","r",stdin);
35         freopen("b.out","w",stdout);
36         n=read(); for(int i=1;i<=n;++i) dis[i]=a[i]=read();
37         sort(dis+1,dis+n+1); new_n=unique(dis+1,dis+n+1)-dis-1;
38         for(int i=1;i<=n;i++) a[i]=lower_bound(dis+1,dis+new_n+1,a[i])-dis+1;
39         double maxn=0.0;
40         for(int i=1;i<=n;i++){
41             int w1=tr.query(1,1,new_n,1,a[i]-1);
42             dp1[i]=w1+dis[a[i]-1];
43             maxn=max(maxn,dp1[i]*1.0);
44             tr.insert(1,1,new_n,a[i],dp1[i]);
45         }
46         memset(tr.maxn,0,sizeof(tr.maxn));
47         for(int i=n;i;i--){
48             int w2=tr.query(1,1,new_n,1,a[i]-1);
49             dp2[i]=w2+dis[a[i]-1];
50             tr.insert(1,1,new_n,a[i],dp2[i]);
51         }
52         // for(int i=1;i<=n;i++) cout<<dp1[i]<<" "<<dp2[i]<<endl;
53         for(int i=1;i<=n;i++){
54             maxn=max(maxn,(dp1[i]+dp2[i]-dis[a[i]-1])/2.0);
55         } printf("%.3lf\n",maxn);
56         return 0;
57     }
58 }
59 signed main(){return WSN::main();}
View Code

 

T3 矩阵

神仙大模拟

当$n>=3 ,m>=3$时,考虑一个图

+ -  
-   +
  + -

这样的一个小正方形按照上面的符号加起来如果不是$0$,那么他无解,

可以看出上面的是对每种操作都进行了一遍,行列斜都是一加一减

判断无解完成后考虑如何构造

 

 

 如图,每个斜线去消除,保证被削后的第二行和第一行相等,即$a[1][j+1]=a[2][j+1],j \in [1,m-1]$,这里只以列举例,

消行的让$a[i][1]=a[i][2],i \in[3,n]$,这样写是为了让红线特判,让他和$a[1][1]$相等,斜着干完列的竖着把列都干成$0$,

斜着干完行的把行干成$0$,这样就可以消完,因为不合法已经判掉,一定有解,注意要输出步数

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=5005;
15 int n,m,a[NN][NN],step;
16 struct answer{
17     int opt,x,k;
18     inline void print(){write(opt,' ');write(x,' ');write(k,' ');puts("");}
19 }ans[NN];
20 // inline void print(){
21     // for(int i=1;i<=n;i++){
22     //     for(int j=1;j<=m;j++){
23     //         cout<<a[i][j]<<" ";
24     //     } cout<<endl;
25     // }
26 // }
27 inline void spj(){
28     cout<<m<<endl;
29     for(int j=1;j<=m;j++) printf("2 %lld %lld\n",j,-a[1][j]);
30 }
31 namespace WSN{
32     inline short main(){
33         freopen("c.in","r",stdin);
34         freopen("c.out","w",stdout);
35         n=read(); m=read();for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) a[i][j]=read();
36         if(n==1){spj(); return 0; }
37         if(n>=3 && m>=3) for(int i=1;i<=n-2;i++) for(int j=1;j<=m-2;j++)
38             if(a[i][j]-a[i][j+1]-a[i+1][j]+a[i+2][j+1]+a[i+1][j+2]-a[i+2][j+2]!=0) return puts("-1"),0;
39         for(int j=m-1;j;j--){
40             ans[++step]=(answer){3,j-1,a[1][j+1]-a[2][j+1]};
41             for(int jj=j,ii;jj<=m;jj++)
42                 ii=jj-ans[step].x, a[ii][jj]+=ans[step].k;
43         }
44         ans[++step]=(answer){3,1-2,a[1][1]-a[2][1]};
45         for(int jj=1,ii;jj<=m;jj++)
46             ii=jj-ans[step].x, a[ii][jj]+=ans[step].k;
47         for(int j=m;j;j--){
48             ans[++step]=(answer){2,j,-a[1][j]};
49             for(int i=1;i<=n;i++) a[i][j]+=ans[step].k;
50         }
51         // print(); return 0;
52         for(int i=3;i<=n;i++){
53             ans[++step]=(answer){3,1-i,a[i][2]-a[i][1]};
54             for(int ii=i,jj;ii<=n;ii++)
55                 jj=ii+ans[step].x, a[ii][jj]+=ans[step].k;
56         }
57         for(int i=3;i<=n;i++){
58             ans[++step]=(answer){1,i,-a[i][1]};
59             for(int j=1;j<=m;j++) a[i][j]+=ans[step].k;
60         }
61         write(step);
62         for(int i=1;i<=step;i++) ans[i].print();
63         return 0;
64     }
65 }
66 signed main(){return WSN::main();}
View Code

 

T4 花瓶

基础$dp$好想,但是时间都花在了$T1$上,没仔细打$T4$,然后就是斜率优化

 

 比较妙的是排序,让复杂度少了一个二分凸包的$log$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 namespace AE86{
 5     inline int read(){
 6         int x=0,f=1;char ch=getchar();
 7         while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 8         while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;
 9     }inline void write(int x,char opt='\n'){
10         char ch[20];int len=0;if(x<0)x=~x+1,putchar('-');
11         do{ch[len++]=x%10+(1<<5)+(1<<4);x/=10;}while(x);
12         for(register int i=len-1;i>=0;--i)putchar(ch[i]);putchar(opt);}
13 }using namespace AE86;
14 const int NN=5005;
15 int n,s[NN],a[NN],id[NN];
16 int f[NN][NN],q[NN],l,r;
17 inline bool cmp(int a,int b){ return s[a]<s[b];}
18 namespace WSN{
19     inline short main(){
20         freopen("d.in","r",stdin);
21         freopen("d.out","w",stdout);
22         n=read(); for(int i=1;i<=n;i++) a[i]=read(),s[i]=s[i-1]+a[i],id[i]=i;
23         sort(id,id+n+1,cmp); memset(f,-0x3f,sizeof(f));
24         for(int i=0;i<=n;i++) f[i][0]=0;
25         for(int j=1;j<=n;j++){
26             l=1; r=0;
27             for(int k=0;k<=n;k++) if(id[k]<j){
28                 while(l<r && (f[j][q[r]]-f[j][q[r-1]])*(s[id[k]]-s[q[r-1]])<=(f[j][id[k]]-f[j][q[r-1]])*(s[q[r]]-s[q[r-1]])) --r;
29                 q[++r]=id[k];
30             }
31             for(int i=n;~i;i--) if(id[i]>j){
32                 while(l<r && (s[id[i]]-s[j])*(s[q[l+1]]-s[q[l]])<=(f[j][q[l+1]]-f[j][q[l]])) ++l;
33                 f[id[i]][j]=max(f[id[i]][j],f[j][q[l]]+(s[id[i]]-s[j])*(s[j]-s[q[l]]));
34             }
35         }
36         int maxn=0;    for(int i=0;i<n;i++) maxn=max(maxn,f[n][i]);
37         write(maxn);
38         return 0;
39     }
40 }
41 signed main(){return WSN::main();}
View Code

 

posted @ 2021-09-25 19:44  雪域亡魂  阅读(105)  评论(0编辑  收藏  举报