1. 程式人生 > 其它 >2021.8.12考試總結[NOIP模擬37]

2021.8.12考試總結[NOIP模擬37]

T1數列 T2數對 T3最小距離 T4真相

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