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();}
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();}
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();}
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();}