2021.10.17
T1:裂变链接
Problem:
现在有𝑁个异构体在前线排成一排参与战斗,但由于地方火力过于凶猛,异构体们都受到了不同程度的损伤。为了能够让所有异构体继续战斗,避免由于能量不均衡导致的爆炸,异构体们需要使得他们彼此之间的能量值一样。记第𝑖个异构体当前𝑒𝑖的能量,每个时刻,每个异构体都可以做如下三种操作中的一种:
1、传递1的能量给自己左边相邻的异构体(如果存在)。
2、传递1的能量给自己右边相邻的异构体(如果存在)。
3、传递1的能量给自己(摸鱼)。
为了尽快的回到前线作战,异构体们希望在最短的时间内使得所有异构体的能量值一样,问最短时间。数据保证有解。操作过程中自己的能量可以变为负数。
Solution:
每个物体只用考虑能量向左还是向右传递,找到需要传递能量最多的物体即可。
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=100010; 4 int n,z[maxn]; 5 long long sum[maxn]; 6 void read(){ 7 scanf("%d",&n); 8 for(int a=1;a<=n;a++) scanf("%d",&z[a]); 9 } 10 long long work(){ 11 for(int a=1;a<=n;a++) sum[a]=sum[a-1]+z[a]; 12 if(sum[n]%n) return -1; 13 long long ans=0,v=sum[n]/n; 14 for(int a=1;a<=n;a++){ 15 long long l=sum[a-1]-1ll*(a-1)*v; 16 long long r=sum[n]-sum[a]-1ll*(n-a)*v; 17 if(l<0&&r<0) ans=max(ans,-l-r); 18 ans=max(ans,max(abs(l),abs(r))); 19 } 20 return ans; 21 } 22 int main(){ 23 read(); 24 printf("%lld\n",work()); 25 return 0; 26 }
T2:死亡鸽者
Problem:
死亡鸽者最喜欢的事情就是咕咕咕,他的座右铭“风萧萧兮易水寒,壮士一去兮不复返,然鸽子至今未到”也每天被他所忘记。今天,死亡鸽者又要开始咕咕的旅行了。现在有𝑁座城市排成一排,死亡鸽者会从第一座城市一直走到最后一座城市。每个城市都有一个数𝑎𝑖,每次死亡鸽者可以选择取走或者不取走这个数,但想要取走这个数的话要求这个数必须是所有已经取走的数的倍数或者约数。现在问死亡鸽者从第一座城市走到最后一座城市的过程中,最多取走多少个数。
Solution:
所有数的顺序并不影响,按照所有数从小到大排序后可以转化为取倍数问题。利用类似于埃式筛法的思路可以做到O(nlogn)。
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1000010; 4 int n,cnt[maxn],f[maxn]; 5 int main(){ 6 scanf("%d",&n); 7 for(int a=1;a<=n;a++){ 8 int v; 9 scanf("%d",&v); 10 cnt[v]++; 11 f[v]++; 12 } 13 int ans=0; 14 for(int a=1;a<=1000000;a++){ 15 if(f[a]){ 16 if(f[a]>ans) ans=f[a]; 17 for(int b=a+a;b<=1000000;b+=a){ 18 if(cnt[b]&&f[a]+cnt[b]>f[b]) f[b]=f[a]+cnt[b]; 19 } 20 } 21 } 22 printf("%d\n",ans); 23 return 0; 24 }
T3:进阶之灾
Problem:
TarjanLusa 是一款风靡全球的卡牌游戏,在这款游戏中,你需要一层一层的前进,击败像萌死戳、天启骑士等 boss,最终来到心脏面前一决胜负。为了能够有一套更好的卡牌来面对心脏,我们需要在每一层选择更好的卡牌。假设我们总共有𝑁层,在第𝑖层的时候,我们可以从两张卡牌中选择一张加入我们的卡组,这两张卡牌的战斗力分别为𝑎𝑖, 𝑏𝑖。在经过𝑁层的选择之后,我们便会有一套𝑁张卡的卡组,而整套卡组的战斗力取决于卡牌与卡牌之间战斗力差值的绝对值的最小值。但是心脏是一个非常强大的敌人,如果我们不能拥有强大的战斗力,人类就
会一败涂地。所以,现在我们想知道,战斗力最大可能是多少。
Solution:
二分答案。
每次检验的时候会发现,一组卡牌中的一张选了会导致其他某组卡牌必须选另外一张,从而转化为2-SAT问题。
但由于数据范围过大,直接2SAT无法建图,注意到所有的边都是在一个区间里面的边,所以用线段树优化建图即可。
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=200010; 4 const int maxp=maxn+(maxn<<2); 5 const int maxm=maxn+maxp+maxn*40; 6 int n,size,cnt,en,t,dfn[maxp],low[maxp],s[maxp],belong[maxp],pos[maxn]; 7 bool instack[maxp]; 8 struct edge{ 9 int e; 10 edge *next; 11 }*v[maxp],ed[maxm]; 12 void add_edge(int s,int e){ 13 en++; 14 ed[en].next=v[s]; 15 v[s]=ed+en; 16 v[s]->e=e; 17 } 18 struct rec{ 19 int v,p; 20 rec(){} 21 rec(int a,int b){ 22 v=a; 23 p=b; 24 } 25 }z[maxn]; 26 bool operator<(const rec &a,const rec &b){ 27 return a.v<b.v; 28 } 29 void dfs(int p){ 30 t++; 31 dfn[p]=low[p]=t; 32 instack[p]=true; 33 s[++size]=p; 34 for(edge *e=v[p];e;e=e->next){ 35 if(!dfn[e->e]){ 36 dfs(e->e); 37 low[p]=min(low[p],low[e->e]); 38 } 39 else{ 40 if(instack[e->e]) low[p]=min(low[p],dfn[e->e]); 41 } 42 } 43 if(dfn[p]==low[p]){ 44 cnt++; 45 while(s[size]!=p){ 46 belong[s[size]]=cnt; 47 instack[s[size]]=false; 48 size--; 49 } 50 belong[p]=cnt; 51 instack[p]=false; 52 size--; 53 } 54 } 55 void build(int l,int r,int rt){ 56 if(l==r){ 57 add_edge(rt+(n<<1),z[l].p<=n?z[l].p+n:z[l].p-n); 58 return; 59 } 60 int m=(l+r)>>1; 61 build(l,m,rt<<1); 62 build(m+1,r,rt<<1|1); 63 add_edge(rt+(n<<1),(rt<<1)+(n<<1)); 64 add_edge(rt+(n<<1),(rt<<1|1)+(n<<1)); 65 } 66 void insert(int l,int r,int rt,int nowl,int nowr,int p){ 67 if(nowl<=l&&r<=nowr){ 68 add_edge(p,rt+(n<<1)); 69 return; 70 } 71 int m=(l+r)>>1; 72 if(nowl<=m) insert(l,m,rt<<1,nowl,nowr,p); 73 if(m<nowr) insert(m+1,r,rt<<1|1,nowl,nowr,p); 74 } 75 bool check(int k){ 76 en=0; 77 cnt=0; 78 memset(v,0,sizeof(v)); 79 memset(dfn,0,sizeof(dfn)); 80 build(1,(n<<1),1); 81 int r=1,l=1; 82 for(int a=1;a<=(n<<1);a++){ 83 int op,p=z[a].p; 84 if(p<=n) op=pos[p+n]; 85 else op=pos[p-n]; 86 while(r<=a&&z[r].v<=z[a].v-k) r++; 87 if(r<a&&r>=1&&z[r].v>z[a].v-k){ 88 if(op>=r&&op<=a-1){ 89 if(op>r) insert(1,(n<<1),1,r,op-1,z[a].p); 90 if(op<a-1) insert(1,(n<<1),1,op+1,a-1,z[a].p); 91 } 92 else insert(1,(n<<1),1,r,a-1,z[a].p); 93 } 94 while(l<=(n<<1)&&z[l].v<z[a].v+k) l++; 95 l--; 96 if(l>a&&l<=(n<<1)&&z[l].v<z[a].v+k){ 97 if(op>=a+1&&op<=l){ 98 if(op>a+1) insert(1,(n<<1),1,a+1,op-1,z[a].p); 99 if(op<l) insert(1,(n<<1),1,op+1,l,z[a].p); 100 } 101 else insert(1,(n<<1),1,a+1,l,z[a].p); 102 } 103 } 104 for(int a=1;a<=(n<<1);a++) if(!dfn[a]) dfs(a); 105 for(int a=1;a<=n;a++) if(belong[a]==belong[a+n]) return false; 106 return true; 107 } 108 int main(){ 109 scanf("%d",&n); 110 int minv=0x3f3f3f3f,maxv=-0x3f3f3f3f; 111 int x=0; 112 for(int a=1;a<=n;a++){ 113 int v1,v2; 114 scanf("%d%d",&v1,&v2); 115 z[++x]=rec(v1,a); 116 z[++x]=rec(v2,a+n); 117 minv=min(minv,min(v1,v2)); 118 maxv=max(maxv,max(v1,v2)); 119 } 120 if(maxv-minv+1<n){ 121 printf("0\n"); 122 return 0; 123 } 124 sort(z+1,z+x+1); 125 for(int a=1;a<=(n<<1);a++) pos[z[a].p]=a; 126 int l=0,r=1000000001; 127 while(l+1!=r){ 128 int m=(l+r)>>1; 129 if(check(m)) l=m; 130 else r=m; 131 } 132 printf("%d\n",l); 133 return 0; 134 }