AtCoder Grand Contest 049 Partial Solution

8 篇文章 1 订阅
2 篇文章 0 订阅

A A A

给定一张 n n n个点的有向图. n ≤ 100 n\le 100 n100.
每次随机一个存在的点,然后删除它及其可到达的点.
问期望多少次删除使得图为空.

这道题和最近我做的模拟赛的一道题类似:

一开始有 [ 1 , n ] [1,n] [1,n]的正整数,然后每次随机一个存在的数,删掉所有倍数.
问期望多少次删为空. n ≤ 1 0 10 n\le 10^{10} n1010

两者的本质思想是一致的.(不过恶心的地方在于第二题要用 m i n _ 25 min\_25 min_25)
考虑一个数 i i i删除的时候是随机到自己的概率 p i p_i pi.
那么显然 a n s = ∑ p i ans=\sum p_i ans=pi.
因为一次删除序列假设是 a 1 , a 2 , . . . , a m a_1,a_2,...,a_m a1,a2,...,am,那么只有这些被选出来的点记操作次数( m m m),其余的都和操作次数无关,所以我们只要讨论每一个点被选出的概率即可.

更具体地,我们设有 x x x个点能够删除 i i i(包括 i i i自己),那么由它自己删除自己的概率就是 1 x \dfrac 1x x1.

暴力 O ( n 2 ) d f s O(n^2) dfs O(n2)dfs即可.

如果你想练一下 t a r j a n tarjan tarjan我也不拦你

int n, a[N], vis[N], lst[N], now;
char s[N][N]; 
 
void dfs(int x) {
	if(lst[x] == now) return;
	lst[x]=now; vis[x]++;
	FOR(y,n) if(s[x][y] == '1') dfs(y);
}
 
void solve() {
	qr(n);
	FOR(i,n) scanf("%s",s[i]+1);
	for(now=1;now<=n;now++) dfs(now);
	db ans=0;
	FOR(i,n) ans += 1.0/vis[i];
	printf("%.10lf\n",ans); 
} 

B B B

给定俩长度为 n n n的字符串 s , t s,t s,t.
每次操作定义为:
找到一个 n ≥ i > 1 n\ge i>1 ni>1使得 s i = ′ 1 ′ s_i='1' si=1.反转(01互换) s i , s i − 1 s_i,s_{i-1} si,si1.
问最少的操作次数变为 t t t,或者判定无解.
n ≤ 5 e 5 n\le 5e5 n5e5

首先我们来考察一下操作时候的两种情况:

  1. s i = ′ 1 ′ , s i − 1 = ′ 0 ′ s_i='1',s_{i-1}='0' si=1,si1=0.此时就是相当于 s w a p swap swap俩相邻数.
  2. s i = s i − 1 = ′ 1 ′ s_i=s_{i-1}='1' si=si1=1.此时等价于删除俩个相邻的1.

所以可以得出一个无解的情况, s , t s,t s,t的1个数奇偶性不同.

可以发现 1 1 1只能往前挪,所以我们从前往后扫描,令 t i = 1 t_i=1 ti=1贪心匹配最近的 s j = 1 ( i ≤ j ) s_j=1(i\le j) sj=1(ij).
对于一个 s i = 1 s_i=1 si=1,如果能和 t t t匹配就匹配,否则就自取灭亡(和最近的1配对删除)…

T i p : l o n g   l o n g Tip:long~ long Tip:long long

int n;
char a[N], b[N];
 
void out() {puts("-1"); exit(0);}
 
void solve() {
	qr(n);
	scanf("%s%s",a+1,b+1);
	ll ans=0;
	int f=-1,cnt=0;
	FOR(i,n) {
		if(b[i] == '1') cnt++,ans -= i;
		if(a[i] == '1') {
			if(cnt) ans += i,cnt--;
			else ans += f*i,f = -f;
		}
	}
	if(cnt || f == 1) out();
	pr2(ans);
}

C C C

b i b_i bi个写着 a i a_i ai的球.
有无穷个机器人站在一条线上,坐标为 i i i的标号为 i i i.
每次选择一个球,若上面写着 x x x. 如果机器人 x x x存在,那么往前移动一格,如果前面一格有机器人,那么直接把他撞毁.
机器人0是世界的中心,所以你不能破坏它.
为此你可以修改球上的数字.
选择序列可以任意,你需要求出最小的修改次数使得机器人0毫发无损.
在这里插入图片描述

可以看出标号小的机器人为弱势群体,容易被撞飞…
同时显然 a i ≤ b i a_i\le b_i aibi的机器人都可以撞坏 0 0 0.
对于这些危险的机器人,我们首先贪心用他们后面的非危险机器人去撞它.

最后仍然剩余一些机器人 x 1 , x 2 . . . . x m x_1,x_2....x_m x1,x2....xm可以撞0.
首先可以发现改变 m m m个是可以把这 m m m个全部毁掉的,但是这个不够紧.
还有我们可以发现一点: 让危险机器人往前滑 x x x个单位的话,要删除这个机器人我们需要 x x x个球放在其起点的后一个位置,才能删除它,所以先滑后删是不优秀的.
但是还有一种情况我们没有利用就是:先滑不删.
我们只需对危险机器人挪出 b i − a i + 1 b_i-a_i+1 biai+1个,放到后面删除后面的危险机器人即可.
因为前面的所有机器人都可以收到当前机器人的 滑铲.

注意: 被删除的危险机器人也可以用来滑铲.(比赛的时候没想到,错失上分机会,嘤嘤嘤)

int n, a[N], b[N], sta[N], top, t[N];

void solve() {
	qr(n); 
	FOR(i,n) qr(a[i]);
	FOR(i,n) qr(b[i]);
	FOR(i,n) 
		if(a[i] <= b[i]) {//dangerous 
			sta[++top]=i;
			t[i]=1;
		}
		else {
			while(top && a[i]-a[sta[top]] <= b[i]) 
				t[sta[top--]]=0;
		}
	int ans=top,cnt=0;
	REP(i,1,n) {
		if(a[i] > b[i]) continue;
		ans=min(ans,max(b[i]-a[i]+1,cnt));
		cnt += t[i];
	}
	pr2(ans);
}

D D D

求合法的 A A A序列个数,满足:
∑ i = 1 n A i = M , A i ∈ N , 2 A i ≤ A i − 1 + A i + 1 ( i ∈ ( 1 , n ) ) \sum_{i=1}^n A_i=M,A_i\in N,2A_i\le A_{i-1}+A_{i+1}(i\in (1,n)) i=1nAi=M,AiN,2AiAi1+Ai+1(i(1,n))
n , m ≤ 1 e 5 n,m\le 1e5 n,m1e5

背包好题: 考察背包的加入和删除.

首先我们钦定最小值的下标为 m m m.(若有多个相同取下标最小)
那么我们可以通过如下形式构造 A A A.

  1. 先令 A = ( C , C , C . . . C ) ( C ≥ 0 ) A=(C,C,C...C)(C\ge 0) A=(C,C,C...C)(C0).
  2. 执行若干次: 找到 i < m i<m i<m,给 A i , A i − 1 , A i − 2 . . . A 1 A_i,A_{i-1},A_{i-2}...A_1 Ai,Ai1,Ai2...A1分别加上 1 , 2 , 3... i 1,2,3...i 1,2,3...i.(一定要用一次 i = ( m − 1 ) i=(m-1) i=(m1),以保证最小性质成立)
  3. 执行若干次: 找到 i > m i>m i>m,给 A i , A i + 1 . . . . A n A_i,A_{i+1}....A_n Ai,Ai+1....An分别加上 1 , 2 , 3... 1,2,3... 1,2,3....

f ( i ) = ∑ j = 1 i j f(i)=\sum_{j=1}^i j f(i)=j=1ij.
那么对于固定的 m m m,相当于求体积为 M M M的完全背包的方案数:
物品大小分别为 n , f ( 1 ) , f ( 2 ) , . . . f ( m − 1 ) ( a h e a d ) , f ( 1 ) , f ( 2 ) . . . f ( n − m ) ( b e h i n d ) n,f(1),f(2),...f(m-1)(ahead),f(1),f(2)...f(n-m)(behind) n,f(1),f(2),...f(m1)(ahead),f(1),f(2)...f(nm)(behind).
注意到只有 m \sqrt m m 种物品有用,所以预处理复杂度为 O ( m 1.5 ) O(m^{1.5}) O(m1.5)

m m m移动到 m + 1 m+1 m+1时,此时完全背包加入一个物品体积为 f ( m ) f(m) f(m),删除一个 f ( n − m ) f(n-m) f(nm).
所以每次更新一下DP数组即可.

注意到 f ( m − 1 ) f(m-1) f(m1)是钦定的,所以只有 m \sqrt m m 个位置是合法最小值的下标 m m m .
所以总复杂度为 O ( m 1.5 ) O(m^{1.5}) O(m1.5).

int n, m, F[N];

ll f(ll x) {return x*(x+1)/2;}

void add(ll x) {
	for(ll i=x;i<=m;i++)
		ad(F[i] ,F[i-x]);
}

void del(ll x) {
	for(ll i=m-x;i>=0;i--)
		dl(F[i+x],F[i]);
}

void solve() {
	qr(n); qr(m); F[0]=1; add(n);
	FOR(i,n-1) add(f(i));
	ll ans=0;
	FOR(i,n) {
		if(f(i-1) <= m) ad(ans,F[m-f(i-1)]);
		else break;
		add(f(i)); del(f(n-i));
	}
	pr2(ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值