Loading

Noip模拟37 2021.8.12

T1 数列

真是考场上不是数学的乱推柿子,想定理,是数学的没想出来。。

比较悲伤。。。

列柿子不用动脑子,就是没有想出来$EXgcd$解不定方程,淦。。

解处一组解后利用比较显然的性质:

$x+\frac{b}{gcd},y-\frac{a}{gcd}$

$x-\frac{b}{gcd},y+\frac{a}{gcd}$

利用此调整$abs(x)+abs(y)$的最优值,为了快速的搞,使用倍增记录调整的偏移量

%%%大佬$zxs$考场$A$此题!!!$Orz$

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 inline int read(){
 5     int x=0,f=1; char ch=getchar();
 6     while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); }
 7     while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar();}
 8     return x*f;
 9 }
10 inline void write(int x){
11     char ch[20]; int len=0;
12     if(x<0) x=~x+1, putchar('-');
13     do{ ch[len++]=x%10+(1<<5)+(1<<4); x/=10; }while(x);
14     for(int i=len-1;i>=0;--i) putchar(ch[i]); putchar('\n');
15 }
16 int n,a,b,x,y;
17 int la[30],lb[30];
18 int EXgcd(int a,int b,int &x,int &y){
19     if(b==0){x=1;y=0;return a;}
20     int gcd=EXgcd(b,a%b,x,y);
21     int t=x;
22     x=y; y=t-y*(a/b);
23     return gcd;
24 }
25 namespace WSN{
26     inline short main(){
27         scanf("%lld%lld%lld",&n,&a,&b);
28         int gcd=EXgcd(a,b,x,y),ans=0;
29         la[0]=a/gcd; lb[0]=b/gcd;
30         for(int i=1;i<30;++i){
31             la[i]=la[i-1]<<1;
32             lb[i]=lb[i-1]<<1;
33         }
34         while(n--){
35             int m; scanf("%lld",&m); m=abs(m);
36             if(m%gcd!=0) return puts("-1"),0;
37             int xx=(m/gcd)*x,yy=(m/gcd)*y;
38             for(int i=29;i>=0;--i){
39                 if(abs(xx)+abs(yy)>=abs(xx+lb[i])+abs(yy-la[i])) xx+=lb[i],yy-=la[i];
40                 if(abs(xx)+abs(yy)>=abs(xx-lb[i])+abs(yy+la[i])) xx-=lb[i],yy+=la[i];
41             }
42             ans+=abs(xx)+abs(yy);
43         }
44         write(ans);
45         return 0;
46     }
47 }
48 signed main(){return WSN::main();}
View Code

 

T2 数对

魔改队长快跑

鉴于不会$dp$考场上直接跳了。。。。

$dp$原理跟那个题基本一样,改一下判断条件和方程就行

关于贪心的排序,就是按照$a,b$小的那一个升序排列,可以感性理解,这样是比较优的

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 #define lid (id<<1)
 4 #define rid (id<<1|1)
 5 using namespace std;
 6 const int NN=2e5+5;
 7 int n,dis[NN<<1],cnt,new_n;
 8 struct SNOW{int a,b,w;}; SNOW s[NN];
 9 inline bool cmp(SNOW a,SNOW b){return min(a.a,a.b)<min(b.a,b.b);}
10 struct SNOWtree{
11     int ll[NN<<2],rr[NN<<2];
12     int maxn[NN<<2],lzy[NN<<2];
13     inline void pushdown(int id){
14         if(!lzy[id]||ll[id]==rr[id]) return;
15         maxn[lid]+=lzy[id]; maxn[rid]+=lzy[id];
16         lzy[lid]+=lzy[id]; lzy[rid]+=lzy[id];
17         lzy[id]=0;
18     }
19     void build(int id,int l,int r){
20         ll[id]=l; rr[id]=r;
21         if(l==r) return;
22         int mid=(l+r)>>1;
23         build(lid,l,mid);
24         build(rid,mid+1,r);
25     }
26     void update(int id,int l,int r,int v){
27         if(l<=ll[id]&&rr[id]<=r){
28             maxn[id]+=v; lzy[id]+=v;
29             return;
30         }
31         pushdown(id);
32         int mid=(ll[id]+rr[id])>>1;
33         if(l<=mid) update(lid,l,r,v);
34         if(r>mid) update(rid,l,r,v);
35         maxn[id]=max(maxn[lid],maxn[rid]);
36     }
37     void update_sg(int id,int x,int v){
38         if(ll[id]==rr[id]){
39             maxn[id]=max(maxn[id],v);
40             return;
41         }
42         pushdown(id);
43         int mid=(ll[id]+rr[id])>>1;
44         if(x<=mid) update_sg(lid,x,v);
45         else update_sg(rid,x,v);
46         maxn[id]=max(maxn[lid],maxn[rid]);
47     }
48     int query(int id,int l,int r){
49         if(l<=ll[id]&&rr[id]<=r) return maxn[id];
50         pushdown(id);
51         int mid=(ll[id]+rr[id])>>1,ans=0;
52         if(l<=mid) ans=max(ans,query(lid,l,r));
53         if(r>mid) ans=max(ans,query(rid,l,r));
54         return ans;
55     }
56 }tr;
57 namespace WSN{
58     inline short main(){
59         scanf("%lld",&n);
60         for(int i=1;i<=n;i++){
61             scanf("%lld%lld%lld",&s[i].a,&s[i].b,&s[i].w);
62             dis[++cnt]=s[i].a; dis[++cnt]=s[i].b;
63         } sort(dis+1,dis+cnt+1); new_n=unique(dis+1,dis+cnt+1)-dis-1;
64         tr.build(1,1,new_n);
65         for(int i=1;i<=n;i++){
66             s[i].a=lower_bound(dis+1,dis+new_n+1,s[i].a)-dis;
67             s[i].b=lower_bound(dis+1,dis+new_n+1,s[i].b)-dis;
68         }
69         sort(s+1,s+n+1,cmp);
70         for(int i=1;i<=n;i++)
71             if(s[i].a>=s[i].b)
72                 tr.update_sg(1,s[i].a,(tr.query(1,1,s[i].b)+s[i].w));
73             else{
74                 tr.update(1,s[i].a+1,s[i].b,s[i].w);
75                 tr.update_sg(1,s[i].a,(tr.query(1,1,s[i].a)+s[i].w));
76             }
77         printf("%lld\n",tr.query(1,1,new_n));
78         return 0;
79     }
80 }
81 signed main(){return WSN::main();}
View Code

 

T3 最小距离

比较神仙的改了$dij$

先将所有的特殊点放进堆,然后跑正宗$dij$,跑的过程中记录最小值的转移过程,即$pre$数组

这样便可以一遍$dij$求出$dis_x$表示$x$到最近的特殊点距离,$pre_x$表示离$x$最近的特殊点

这样遍历每一条边,更新答案(即枚举边的两个端点,找到他们的源特殊点,用$dis[fr]+e[i].val+dis[to]$更新)

注意如果两端的源特殊点一样直接$continue$即可

 1 #include<bits/stdc++.h>
 2 #define int long long
 3 using namespace std;
 4 const int NN=2e5+5;
 5 int n,m,p,sp[NN],dis[NN],ans[NN],pre[NN];
 6 bool vis[NN];
 7 struct node{
 8     int q,data;
 9     friend bool operator<(node a,node b){return a.data>b.data;}
10 }; priority_queue<node> Q;
11 struct SNOW{int from,to,val,next;};SNOW e[NN<<1]; int head[NN],rp;
12 inline void add(int x,int y,int z){e[++rp]=(SNOW){x,y,z,head[x]};head[x]=rp;}
13 inline void dij(){
14     int x,y; for(int i=0;i<=n;i++) vis[i]=0;
15     for(int i=0;i<=n;i++) dis[i]=1e14;
16     for(int i=1;i<=p;i++) dis[sp[i]]=0,Q.push((node){sp[i],0}),pre[sp[i]]=sp[i];
17     while(!Q.empty()){
18         x=Q.top().q,y=Q.top().data; Q.pop();
19         if(!vis[x]){
20             vis[x]=1;
21             for(int i=head[x];i;i=e[i].next){
22                 if(dis[e[i].to]>y+e[i].val){
23                     dis[e[i].to]=y+e[i].val;
24                     pre[e[i].to]=pre[x];
25                     Q.push((node){e[i].to,dis[e[i].to]});
26                 }
27             }
28         }
29     }
30 }
31 namespace WSN{
32     inline short main(){
33         scanf("%lld%lld%lld",&n,&m,&p);
34         for(int i=1;i<=p;i++) scanf("%lld",&sp[i]);
35         for(int i=1,u,v,w;i<=m;i++){
36             scanf("%lld%lld%lld",&u,&v,&w);
37             add(u,v,w); add(v,u,w);
38         }dij();
39         for(int i=0;i<=n;i++) ans[i]=1e14;
40         for(int i=1;i<=rp;i+=2){
41             int fr=e[i].from,to=e[i].to,vl=e[i].val;
42             if(pre[fr]==pre[to]) continue;
43             ans[pre[fr]]=min(dis[fr]+vl+dis[to],ans[pre[fr]]);
44             ans[pre[to]]=min(dis[fr]+vl+dis[to],ans[pre[to]]);
45         }
46         for(int i=1;i<=p;i++) printf("%lld ",ans[sp[i]]);
47         return 0;
48     }
49 }
50 signed main(){return WSN::main();}
View Code

 

T4 真相

题面过于真实,考场上流下来自弱者的眼泪。。。。。。

 

 然后就$100+100+100+100=400$。。。

好了好了,开始说题,我们设$为预言家(这里是引用$Deepinc$学长的叫法)

如果没有预言家,我们直接找一个人开始递推答案最后判断即可

如果有,就将每个语言家开一块,分开处理每个块里面的真假,初始我们假定预言家都是真话,递推处理

预言家结构体记录四个值,分别表示预言人数,块内真话人数,假话人数,是否合并块

然后将预言人数相同的合并,记录一个值$cntf$表示总的谎话人数,最后判断就行了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int NN=1e5+5;
 4 int T,n,num,tmp;
 5 struct SNOW{
 6     char ch[3];
 7     int k;
 8 }ren[NN];
 9 bool flag=0,pre[20];
10 inline void judge(){
11     pre[n+1]=pre[1];
12     ren[n+1]=ren[1];
13     for(int i=1;i<=n;i++){
14         if(pre[i]){
15             if(ren[i].ch[0]=='+'){
16                 if(!pre[i+1]){flag=1;break;}
17             }
18             else if(ren[i].ch[0]=='-'){
19                 if(pre[i+1]){flag=1;break;}
20             }
21             else{
22                 if(ren[i].k!=num){flag=1;break;}
23             }
24         }
25         else{
26             if(ren[i].ch[0]=='+'){
27                 if(pre[i+1]){flag=1;break;}
28             }
29             else if(ren[i].ch[0]=='-'){
30                 if(!pre[i+1]){flag=1;break;}
31             }
32             else{
33                 if(ren[i].k==num){flag=1;break;}
34             }
35         }
36     }
37 }
38 namespace WSN{
39     inline short main(){
40         scanf("%d",&T);
41         while(T--){
42             scanf("%d",&n); tmp=0;
43             memset(ren,0,sizeof(ren));
44             for(int i=1;i<=n;i++){
45                 scanf("%s",ren[i].ch);
46                 if(ren[i].ch[0]=='+'||ren[i].ch[0]=='-') continue;
47                 scanf("%d",&ren[i].k);
48             }
49             for(int i=0;i<(1<<n);i++){
50                 int sta=i;  num=__builtin_popcount(i);
51                 for(int j=1;j<=n;j++) pre[j]=sta&1,sta>>=1;
52                 flag=0; judge();
53                 if(!flag){puts("consistent");break;}
54                 else ++tmp;
55                 if(tmp==(1<<n)){puts("inconsistent");break;}
56             }
57         }
58         return 0;
59     }
60 }
61 signed main(){return WSN::main();}
暴力
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int NN=1e5+5;
 4 int T,n,con,inc,k[NN],opt[NN],t[NN],f,cnt;
 5 char ch[3];
 6 struct SNOW{
 7     int K,tr,fa,u;
 8     friend bool operator<(SNOW a,SNOW b){return a.K<b.K;}
 9 }J[NN];
10 inline bool spj(){
11     t[1]=1;for(int i=2;i<=n;i++) t[i]=t[i-1]^opt[i-1];
12     if(t[1]==(t[n]^opt[n])) return 1;
13     t[1]=0;for(int i=2;i<=n;i++) t[i]=t[i-1]^opt[i-1];
14     if(t[1]==(t[n]^opt[n])) return 1;
15     return 0;
16 }
17 namespace WSN{
18     inline short main(){
19         scanf("%d",&T);
20         while(T--){
21             scanf("%d",&n);    f=cnt=con=inc=0;
22             for(int i=1;i<=n;i++){
23                 scanf("%s",ch);
24                 if(ch[0]=='$'){f=1;scanf("%d",&k[i]);opt[i]=-1;}
25                 else if(ch[0]=='+') opt[i]=0; else opt[i]=1;
26             }
27             if(!f){puts(spj()?"consistent":"inconsistent");continue;}
28             for(int i=1;i<=n;i++) if(opt[i]==-1){
29                 int j=i-1; if(!j) j=n;
30                 t[i]=1;
31                 J[++cnt]=(SNOW){k[i],1,0,0};
32                 while(opt[j]!=-1){
33                     t[j]=t[(j+1)>n?1:(j+1)]^opt[j];
34                     if(t[j]) J[cnt].tr++;
35                     else J[cnt].fa++;
36                     j--; if(!j) j=n;
37                 }
38             }
39             sort(J+1,J+cnt+1);
40             int last=0; J[0].K=-20050730;
41             for(int i=1;i<=cnt;i++){
42                 if(J[i].K==J[last].K) J[last].tr+=J[i].tr,J[last].fa+=J[i].fa,J[i].u=1;
43                 else last=i;
44             }
45             int cntf=0;
46             for(int i=1;i<=cnt;i++) if(!J[i].u) cntf+=J[i].fa;
47             for(int i=1;i<=cnt;i++) if(!J[i].u) if(J[i].K==cntf-J[i].fa+J[i].tr) con=1;
48             for(int i=1;i<=cnt;i++) if(J[i].K==cntf) inc=1;
49             puts((con||!inc)?"consistent":"inconsistent");
50         }
51         return 0;
52     }
53 }
54 signed main(){return WSN::main();}
View Code

 

posted @ 2021-08-12 21:33  雪域亡魂  阅读(67)  评论(0编辑  收藏  举报