2021.10.15
T1:
Problem:
魔术师的桌子上有 n 个杯子排成一行,编号为 1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品。花费 c_ij 元,魔术师就会告诉你杯子 i,i+1,…,j 底下藏有球的总数的奇偶性。
采取最优的询问策略,你至少需要花费多少元,才能保证猜出哪些杯子底下藏着球?
Code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 int n,m,f[2010]; 4 long long ans; 5 struct edge{ 6 int pa,pb; 7 long long len; 8 }p[2010010]; 9 int find(int x){ 10 return (f[x]==x)?x:(f[x]=find(f[x])); 11 } 12 bool cmp(const edge &a,const edge &b){ 13 return a.len<b.len; 14 } 15 int main(){ 16 scanf("%d",&n); 17 int i,j,a,b; 18 for(i=1;i<=n;i++){ 19 for(j=i;j<=n;j++){ 20 p[++m].pa=i-1; 21 p[m].pb=j; 22 scanf("%lld",&p[m].len); 23 } 24 } 25 sort(p+1,p+m+1,cmp); 26 for(i=1;i<=n;i++) f[i]=i; 27 for(i=1,j=0;i<=m;i++){ 28 a=find(p[i].pa); 29 b=find(p[i].pb); 30 if(a!=b){ 31 f[a]=b; 32 ans+=p[i].len; 33 j++; 34 if(j==n){ 35 printf("%lld",ans); 36 return 0; 37 } 38 } 39 } 40 }
T2:双面扑克牌
Problem:
Makik 有一副全球限量绝版独家纪念版扑克牌。
这副扑克牌很特殊,一共有 n 张,且是双面的,每一面都有一个数字,设正面为 a[i],背面为 b[i]。不同于普通的扑克牌只有 A~K,这些数字可能会很大。Makik 将这副扑克牌拿到了班里,并且按顺序在桌子上摆成一排,于是他的 m 个好基友来欣(破)赏(坏)他的扑克牌了。
他的第 i 个基友会选择欣赏他的第 c[i]和 d[i]个位置上的扑克牌,并在 Makik 眨眼瞬间以超快的手速交换他们。
但是 Makik 从风声中感到了扑克牌发生了变化,他现在想知道,每次他的基友交换了扑克牌后,能否通过任意翻转扑克牌但是不改变位置顺序的情况下,使得扑克牌朝上一面的数值形成一个单调不下降的序列?
Code:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=200005; 4 const int inf=1000000000; 5 int n,m,a[maxn][2],w[maxn*4][2]; 6 void updata(int d,int l,int r){ 7 int mid=(l+r)/2; 8 w[d][0]=w[d][1]=inf; 9 if(w[d<<1][0]<=a[mid+1][0]) w[d][0]=min(w[d][0],w[d<<1|1][0]); 10 if(w[d<<1][0]<=a[mid+1][1]) w[d][0]=min(w[d][0],w[d<<1|1][1]); 11 if(w[d<<1][1]<=a[mid+1][0]) w[d][1]=min(w[d][1],w[d<<1|1][0]); 12 if(w[d<<1][1]<=a[mid+1][1]) w[d][1]=min(w[d][1],w[d<<1|1][1]); 13 } 14 void build(int d,int l,int r){ 15 if(l==r){ 16 w[d][0]=a[l][0]; 17 w[d][1]=a[l][1]; 18 return ; 19 } 20 int mid=(l+r)/2; 21 build(d<<1,l,mid); 22 build(d<<1|1,mid+1,r); 23 updata(d,l,r); 24 } 25 void modify(int d,int l,int r,int x){ 26 if(l==r){ 27 w[d][0]=a[x][0]; 28 w[d][1]=a[x][1]; 29 return ; 30 } 31 int mid=(l+r)/2; 32 if(x<=mid) modify(d<<1,l,mid,x); 33 else modify(d<<1|1,mid+1,r,x); 34 updata(d,l,r); 35 } 36 int main(){ 37 scanf("%d",&n); 38 for(int i=1;i<=n;i++){ 39 scanf("%d%d",&a[i][0],&a[i][1]); 40 } 41 build(1,1,n); 42 scanf("%d",&m); 43 while(m--){ 44 int x,y; 45 scanf("%d%d",&x,&y); 46 swap(a[x][0],a[y][0]); 47 swap(a[x][1],a[y][1]); 48 modify(1,1,n,x); 49 modify(1,1,n,y); 50 if(w[1][0]<inf||w[1][1]<inf) puts("TAK"); 51 else puts("NIE"); 52 } 53 return 0; 54 }
T3:Makik赛道
Problem:
“我和博尔特五五开”Makik 站在操场上对着基友们如是说道。
为了证明自己,Makik 和基友们一共 n 个人决定进行一场另类赛跑。因为他们每个人都是 178cm 且 100kg的体育健将,所以他们从跑道起点到终点的时间惊人的一致:都需要 S 分钟。现在规定每个人从起点开跑时间至少需要互相间隔一分钟的时间,并且,由于赛道很窄,任意时刻,赛道上所有人的狂奔方向必须是一致的。每个人必须从起点跑道终点后再回到起点。
现在给出 n、S 和 n 个人的出发时间,请你帮忙求出最迟回到起点的人的最早时间。
Code:
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 inline void down(ll &x,const ll &y){ 5 if(x>y) x=y; 6 } 7 const int maxn=1100000; 8 int n,S; 9 int a[maxn]; 10 ll f[maxn]; 11 int q[maxn],head,tail; 12 int main(){ 13 scanf("%d%d",&n,&S); 14 a[0]=-1; 15 for(int i=1;i<=n;i++){ 16 scanf("%d",&a[i]); 17 if(a[i]<=a[i-1]) a[i]=a[i-1]+1; 18 } 19 int j=0; 20 head=1,tail=0; 21 for(int i=1;i<=n;i++){ 22 while(j+1<i&&f[j+1]-(j+1)-1<=a[i]-i) j++; 23 while(head<=tail&&q[head]<=j) head++; 24 f[i]=a[i]-i-j; 25 if(head<=tail) down(f[i],f[q[head]]-(q[head]<<1)-1); 26 f[i]+=(S<<1)+(i<<1)-1; 27 while(head<=tail&&f[q[tail]]-(q[tail]<<1)>f[i]-(i<<1)) tail--; 28 q[++tail]=i; 29 } 30 printf("%lld\n",f[n]); 31 return 0; 32 }