2021.8.12考试总结[NOIP模拟37]

T1 数列


考场上切掉的简单题。

$a$,$b$与数列中数的正负值对答案无关。全当作正数计算即可。

$exgcd$解未知数系数为$a$,$b$,加和为$gcd(a,b)$的不定方程组,再枚举每个数。如果不为$gcd(a,b)$倍数则无解,否则将解的绝对值加和调整至最小。

调整可以分类讨论,我写了不用动脑子的倍增。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=1e5+5;
 5 int n,a,b,l[NN],ans,x,y,gcd,epx[30],epy[30],tmx,tmy,res;
 6 inline int qabs(int x){ return x<0?(~x+1):x; }
 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(); }
11     return x*f;
12 }
13 inline void write(int x,char sp){
14     char ch[20]; int len=0;
15     if(x<0){ putchar('-'); x=~x+1; }
16     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
17     for(int i=len-1;i>=0;--i) putchar(ch[i]); putchar(sp);
18 }
19 int exgcd(int a,int b){
20     if(!b){ x=1; y=0; return a; }
21     int g=exgcd(b,a%b),z=x;
22     x=y; y=z-y*(a/b);
23     return g;
24 }
25 signed main(){
26     n=read(); a=qabs(read()); b=qabs(read());
27     if(a>b) swap(a,b);
28     for(int i=1;i<=n;i++) l[i]=qabs(read());
29     gcd=exgcd(a,b); epx[0]=b/gcd; epy[0]=a/gcd;
30     for(int i=1;i<30;i++){
31         epx[i]=epx[i-1]<<1;
32         epy[i]=epy[i-1]<<1;
33     }
34     for(int i=1;i<=n;i++){
35         if(l[i]%gcd){ puts("-1"); return 0; }
36         tmx=l[i]/gcd*x; tmy=l[i]/gcd*y;
37         for(int j=29;j>=0;j--){
38             if(qabs(tmx+epx[j])+qabs(tmy-epy[j])<qabs(tmx)+qabs(tmy)) tmx+=epx[j], tmy-=epy[j];
39             if(qabs(tmx-epx[j])+qabs(tmy+epy[j])<qabs(tmx)+qabs(tmy)) tmx-=epx[j], tmy+=epy[j];
40         }
41         ans+=qabs(tmx)+qabs(tmy);
42     }
43     write(ans,'\n');
44     return 0;
45 }
T1

T2 数对


乍一看好像是道原题,结果元素可以随意排列,直接人傻了。

结果直接乱搞排序能切。($min(a,b)$,$a*b$)人又傻了。

正解是按加和排序。对$a_i<b_j$,$a_j>b_i$,$i$放在前面,反之$i$放在后面。对$a_i<b_j$,$a_j<b_i$和$a_j<b_i$,$a_i<b_j$两种情况$i$,$j$顺序任意。因此按加和排序即可。

线段树以最大$a$为下标建树,支持区间查询,区间加,单点修改。

一个道理的原题题解:

(这个原题是$a_i$必须大于等于$b_j$,反向理解一下啦~~)

 $code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define ld rt<<1
 4 #define rd (rt<<1)|1
 5 using namespace std;
 6 const int NN=2e5+5;
 7 int n,has[NN<<1],ext,cnt;
 8 struct pairs{ int a,b,w; }p[NN],AA[10];
 9 inline bool cmp(pairs x,pairs y){ return (x.a+x.b)<(y.a+y.b); }
10 inline int read(){
11     int x=0,f=1; char ch=getchar();
12     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
13     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
14     return x*f;
15 }
16 inline void write(int x,char sp){
17     char ch[20]; int len=0;
18     if(x<0){ putchar('-'); x=~x+1; }
19     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
20     for(int i=len-1;i>=0;--i) putchar(ch[i]); putchar(sp);
21 }
22 struct segment_tree{
23     int laz[NN<<2],mx[NN<<2];
24     void pushup(int rt){
25         mx[rt]=max(mx[ld],mx[rd]);
26     }
27     void pushdown(int rt){
28         laz[ld]+=laz[rt]; laz[rd]+=laz[rt];
29         mx[ld]+=laz[rt]; mx[rd]+=laz[rt];
30         laz[rt]=0;
31     }
32     void update(int rt,int l,int r,int pos,int v){
33         if(l==r){
34             mx[rt]=max(mx[rt],v);
35             return;
36         }
37         pushdown(rt);
38         int mid=l+r>>1;
39         if(pos<=mid) update(ld,l,mid,pos,v);
40         else update(rd,mid+1,r,pos,v);
41         pushup(rt);
42     }
43     void modify(int rt,int l,int r,int opl,int opr,int v){
44         if(l>=opl&&r<=opr){
45             mx[rt]+=v;
46             laz[rt]+=v;
47             return;
48         }
49         pushdown(rt);
50         int mid=l+r>>1;
51         if(opl<=mid) modify(ld,l,mid,opl,opr,v);
52         if(opr>mid) modify(rd,mid+1,r,opl,opr,v);
53         pushup(rt);
54     }
55     int query(int rt,int l,int r,int opl,int opr){
56         if(l>=opl&&r<=opr) return mx[rt];
57         pushdown(rt);
58         int mid=l+r>>1,ans=0;
59         if(opl<=mid) ans=max(ans,query(ld,l,mid,opl,opr));
60         if(opr>mid) ans=max(ans,query(rd,mid+1,r,opl,opr));
61         return ans;
62     }
63 }s;
64 int dp(){
65     for(int i=1;i<=n;i++)
66         if(p[i].a>=p[i].b)
67             s.update(1,1,ext,p[i].a,s.query(1,1,ext,1,p[i].b)+p[i].w);
68         else{
69             s.modify(1,1,ext,p[i].a+1,p[i].b,p[i].w);
70             s.update(1,1,ext,p[i].a,s.query(1,1,ext,1,p[i].a)+p[i].w);
71         }
72     return s.query(1,1,ext,1,ext);
73 }
74 signed main(){
75     n=read();
76     for(int i=1;i<=n;i++)
77         has[++cnt]=p[i].a=read(), has[++cnt]=p[i].b=read(), p[i].w=read();
78     sort(has+1,has+cnt+1);
79     ext=unique(has+1,has+cnt+1)-has-1;
80     for(int i=1;i<=n;i++){
81         p[i].a=lower_bound(has+1,has+ext+1,p[i].a)-has;
82         p[i].b=lower_bound(has+1,has+ext+1,p[i].b)-has;
83     }
84     sort(p+1,p+n+1,cmp);
85     write(dp(),'\n');
86     return 0;
87 }
T2

T3 最小距离


多源最短路?

具体是跑多个源点的$dijstra$,$dis$记离该点最近的特殊点与该点的距离,$pre$记离该点最近的特殊点。

更新答案时枚举每条边,如果两个端点的$pre$不同就更新两个$pre$的答案。

$code:$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=4e5+5;
 5 int n,m,p,d[NN],st[NN<<1],to[NN<<1],nex[NN<<1],head[NN],w[NN],num,ans[NN],dis[NN],pre[NN];
 6 struct node{ 
 7     int yd,id,v; 
 8     bool operator<(const node &a)const{ return a.v<v; }
 9 }c;
10 inline int read(){
11     int x=0,f=1; char ch=getchar();
12     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
13     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
14     return x*f;
15 }
16 inline void write(int x,char sp){
17     char ch[20]; int len=0;
18     if(x<0){ putchar('-'); x=~x+1; }
19     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
20     for(int i=len-1;i>=0;--i) putchar(ch[i]); putchar(sp);
21 }
22 inline void add(int a,int b,int c){
23     to[++num]=b; nex[num]=head[a]; head[a]=num; w[num]=c; st[num]=a;
24     to[++num]=a; nex[num]=head[b]; head[b]=num; w[num]=c; st[num]=b;
25     if(n==p) ans[a]=min(ans[a],c), ans[b]=min(ans[b],c);
26 }
27 inline void dij(){
28     priority_queue<node>q;
29     bool vis[NN]={0};
30     for(int i=1;i<=n;i++) dis[i]=1e18;
31     for(int i=1;i<=p;i++){
32         c.id=d[i]; c.v=0; dis[d[i]]=0; pre[d[i]]=d[i];
33         q.push(c);
34     }
35     while(!q.empty()){
36         int x=q.top().id,y=q.top().v; q.pop();
37         if(vis[x]) continue;
38         vis[x]=1;
39         for(int i=head[x];i;i=nex[i]){
40             int v=to[i];
41             if(dis[v]<=y+w[i]) continue;
42             dis[v]=y+w[i]; pre[v]=pre[x];
43             c.id=v; c.v=dis[v];
44             q.push(c);
45         }
46     }
47 }
48 signed main(){
49     n=read(); m=read(); p=read();
50     for(int i=1;i<=n;i++) ans[i]=1e18;
51     for(int i=1;i<=p;i++) d[i]=read();
52     for(int i=1;i<=m;i++){
53         int a=read(),b=read(),c=read();
54         add(a,b,c);
55     }
56     dij();
57     for(int i=1;i<=num;i+=2){
58         int s=st[i],t=to[i];
59         if(pre[s]==pre[t]) continue;
60         ans[pre[s]]=min(ans[pre[s]],w[i]+dis[s]+dis[t]);
61         ans[pre[t]]=min(ans[pre[t]],w[i]+dis[s]+dis[t]);
62     }
63     for(int i=1;i<=p;i++) 
64         write(ans[d[i]],i==n?'\n':' ');
65     return 0;
66 }
T3

T4 真相


分类讨论有没有人断言有几个真话。

如果没有,所有人的话可以构成一个环,找一个人枚举他的话真假,判断是否矛盾即可。

如果有,所有人的话会构成多个以这种话为结尾的块。枚举这种话不同的人数,令它为真。

与它相同的话都为真,不同的话为假,可以递推出所有人话的真假,比较真话数量是否符合即可。

$code:$

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int NN=2e5+5;
 4 int t,n,opt[NN],k[NN],pcnt,last,tot;
 5 bool flag,con,inc,tmp[NN];
 6 char op;
 7 struct node{ 
 8     int k,t,f,u; 
 9     bool operator<(const node &a)const{ return a.k<k; }
10 }p[NN];
11 inline int read(){
12     int x=0,f=1; char ch=getchar();
13     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
14     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
15     return x*f;
16 }
17 inline void write(int x,char sp){
18     char ch[20]; int len=0;
19     if(x<0){ putchar('-'); x=~x+1; }
20     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
21     for(int i=len-1;i>=0;--i) putchar(ch[i]); putchar(sp);
22 }
23 bool judge(){
24     tmp[1]=1;
25     for(int i=2;i<=n;i++) tmp[i]=tmp[i-1]^opt[i-1];
26     if(tmp[1]==tmp[n]^opt[n]) return 1;
27     tmp[1]=0;
28     for(int i=2;i<=n;i++) tmp[i]=tmp[i-1]^opt[i-1];
29     if(tmp[1]==tmp[n]^opt[n]) return 1;
30     return 0;
31 }
32 void clear(){
33     pcnt=last=tot=flag=con=inc=0;
34 }
35 signed main(){
36     t=read();
37     while(t--){    
38         n=read(); clear();
39         for(int i=1;i<=n;i++){
40             cin>>op;
41             if(op=='$') flag=1, k[i]=read(), opt[i]=-1;
42             if(op=='+') opt[i]=0;
43             if(op=='-') opt[i]=1;
44         }
45         if(!flag){ puts(judge()?"consistent":"inconsistent"); continue; }
46         for(int i=1;i<=n;++i){
47             if(opt[i]!=-1) continue;
48             int j=i-1;
49             if(!j)j=n;
50             tmp[i]=1;
51             p[++pcnt]=(node){k[i],1,0,0};
52             while(opt[j]!=-1){
53                 tmp[j]=tmp[j==n?1:(j+1)]^opt[j];
54                 if(tmp[j]) p[pcnt].t++;
55                 else p[pcnt].f++;
56                 j--;if(!j)j=n;
57             }
58         }
59         sort(p+1,p+pcnt+1);
60         p[0].k=-20050410;
61         for(int i=1;i<=pcnt;++i)
62             if(p[i].k==p[last].k)p[last].t+=p[i].t,p[last].f+=p[i].f,p[i].u=1;
63             else last=i;
64         int tot=0;
65         for(int i=1;i<=pcnt;++i) if(!p[i].u) tot+=p[i].f;
66         for(int i=1;i<=pcnt;++i) if(!p[i].u) if(p[i].k==tot-p[i].f+p[i].t) con=1;
67         for(int i=1;i<=pcnt;++i) if(p[i].k==tot) inc=1;
68         puts((con||!inc)?"consistent":"inconsistent");
69     }
70     return 0;
71 }
T4

 

posted @ 2021-08-12 20:32  keen_z  阅读(54)  评论(0编辑  收藏  举报