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 }
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 }
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 }
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 }