首页 > 其他分享 >AGC066 题解

AGC066 题解

时间:2024-04-02 22:00:58浏览次数:27  
标签:AAB 题解 tt 50 AGC066 BAA ll

题解:AT_agc066_a [AGC066A] Adjacent Difference

笑点解析:没有必要将总成本最小化。


我们将格子间隔的黑白染色(显然有两种染色方法),对于黑点我们要求它是奇数倍 \(d\),对于白点我们要求它是偶数倍 \(d\),这样一定满足相邻格子相差至少 \(d\)。

因为两种染色方法的代价和为 \(dN^2\),所以两种方法中至少有一种满足代价小于 \(\frac{1}{2}dN^2\),容易实现:

ll n, m, ans = 1e15, Case=1;
ll a[N][N], b[N][N], c[N][N];
void solve() {
	input(n, m);
	for(ll i = 1; i <= n; i++) {
		for(ll j = 1; j <= n; j++) {
			input(a[i][j]);
		}
	}
	for(ll x = 0; x <= 1; x ++) {
		ll sum = 0;
		for(ll i = 1; i <= n; i ++) {
			for(ll j = 1; j <= n; j ++) {
				ll k = a[i][j] / m;
				if((i + j + k + x) % 2 == 0) {
					if(a[i][j] < 0) k --;
					else k ++;
				}
				b[i][j] = k * m;
				sum += abs(b[i][j] - a[i][j]);
			}
		}
		if(sum < ans) {
			for(ll i = 1; i <= n; i ++) {
				for(ll j = 1; j <= n; j ++) {
					c[i][j] = b[i][j];
				}
			}
			ans = sum;
		}
	}
	for(ll i = 1; i <= n; i ++) {
		for(ll j = 1; j <= n; j ++) {
			print(c[i][j]);
		}
		putchar('\n');
	}
//	print(ans);
}

题解:AT_agc066_b [AGC066B] Decreasing Digit Sums

题目大意:给定 \(n\),求一个 \(x\),使得对于任意的 \(1\le i\le n\),满足 \(d(2^{i-1}x)>d(2^ix)\)。其中 \(d(x)\) 指 \(x\) 的数位和。

我们发现,答案是具有单调性的,也就是对于 \(n=50\) 的答案,同样适用于 \(n<50\) 的情况。

所以我们只用考虑 \(n=50\) 的答案即可。


按照直观的感受,给定任意的 \(x\) 与 \(y\),已知 \(x>y\),那么 \(d(x)\) 大于 \(d(y)\) 的概率会比较大。

但是随着 \(i\) 的增加,\(2^ix\) 也会随之增加,所以我们要考虑减小 \(d(2^ix)\)。

我们发现,如果某一个数位为 \(0\),对于 \(d\) 函数就没有贡献。所以考虑构造一个 \(x\),使得它乘上 \(2^i\) 可以产生若干个 \(0\)。所以设 \(x=5^{50}a\),那么 \(d(2^ix)=d(2^i5^{50}a)=d(10^i5^{50-i}a)=d(5^{50-i}a)\),此时随着 \(i\) 的增加,\(5^{50-i}a\) 也会随之减小,那么 \(d(5^{50-i}a)\) 肯定也会趋于减小。具体:


但是这样仍旧不是单调递减的,但是它是趋于单调递减的,所以我们可以考虑把它们拼接起来,这样平均下来,单调递减的概率就会大大上升。

我们随机得到 \(a_1,a_2,\cdots,a_k\),然后将这 \(k\) 个系数组成的数用 \(0\) 连接起来,这样就可以保证它单调递减的概率比较大:

下面代码中的 bign 是高精度,check 是判断是否合法的函数:

ll n = 50, k = 100;
bign a = 1, ans;
int main() {
	for(ll i = 1; i <= 50; i ++) a = a * 5;
	while(true) {
		ans = 0;
		for(ll i = 1; i <= k; i ++) {
			ll x = rnd() % 100 + 1;
			bign tmp = a * x;
			for(ll j = 1; j <= tmp.len + 50; j ++) ans = ans * 10;
			ans = ans + tmp;
		}
		if(check(ans)) {
			cout << ans << endl;
			break;
		}
	}
	return 0;
}

一种可能的结果

题解:AT_agc066_c [AGC066C] Delete AAB or BAA

这题评黑我觉得有点过了。其实还是比较好想的。

考虑一个区间怎么才能被消除掉:它满足可以分成若干个满足以下条件的子串:每个子串都满足 \(\tt A\) 的数量是 \(\tt B\) 的两倍,左端点右端点是 \(\tt B\)。

证明可以让时间倒流,我们在这个字符串内不断添加 \(\tt AAB\) 或 \(\tt BAA\)。

如果一个字符串是空字符串,添加 \(\tt AAB\) 或 \(\tt BAA\) 明显符合。

如果一个字符串符合条件,那么在两端添加 \(\tt AAB\) 或 \(\tt BAA\) 相当于添加了一个新的符合条件的子串,如果在中间添加 \(\tt AAB\) 或 \(\tt BAA\),字符串两端的字符仍旧不变,依旧符合。

所以通过归纳法可以证明。


所以我们设 \(x_i\) 表示 \(1\sim i\) 中 \(\tt B\) 的数量的两倍减去 \(\tt A\) 的数量。若 \(x_l=x_r\),则 \([l+1,r]\) 明显是一个可以被消除掉的字符串。

所以我们容易设 \(f_i\) 表示处理到第 \(i\) 个字符,最少不删掉的字符的数量,明显我们需要最小化它。

那么有转移方程:

\[f_i=\begin{cases} f_{i-1}+1 \\ f_j & x_i=x_j,s_{j+1}={\tt B} \\ f_j & x_i=x_j,s_{i}={\tt B} \end{cases} \]

对于第二、三种情况,我们可以用两个 map 来储存每种 \(x\) 下的最小 \(f\) 值。

这里不使用 \(f_i\) 表示最多不删除的字符数量的原因是因为不太好打。

void solve() {
	map<ll, ll> ha, hb;
	scanf("%s", s + 1);
	n = strlen(s + 1);
	for(ll i = 1; i <= n; i ++) {
		a[i] = a[i - 1], b[i] = b[i - 1];
		if(s[i] == 'A') {
			a[i] ++;
		}
		else {
			b[i] ++;
		}
		x[i] = a[i] - 2 * b[i];
		ha[x[i]] = hb[x[i]] = inf;
	}
	ha[0] = hb[0] = inf;
	for(ll i = 1; i <= n; i ++) {
		f[i] = inf;
	}
	if(s[1] == 'A') {
		ha[0] = 0;
	} else {
		hb[0] = 0;
	}
	for(ll i = 1; i <= n; i ++) {
		f[i] = min(f[i], f[i - 1] + 1);
		if(s[i] == 'A') {
			f[i] = min(f[i], hb[x[i]]);
		} else {
			f[i] = min(f[i], ha[x[i]]);
			f[i] = min(f[i], hb[x[i]]);
		}
		if(s[i + 1] == 'A') {
			ha[x[i]] = min(ha[x[i]], f[i]);
		} else {
			hb[x[i]] = min(hb[x[i]], f[i]);
		}
	}
	print((n - f[n]) / 3);
	putchar('\n');
}

标签:AAB,题解,tt,50,AGC066,BAA,ll
From: https://www.cnblogs.com/znpdco/p/18111598

相关文章

  • [ABC259F] Select Edges 题解
    很容易想到树形dp。考虑在有根树内,每个点都有两种状态:不选自己和父亲的边;要选自己和父亲的边。那么单独对于子树内部而言,就要分两种情况:最多可以向\(d_i\)个孩子连边,对应上述第一种情况,我们称之为\(f_i\);最多可以向\(d_i-1\)个孩子连边,对应上述第二种情况,我们称之......
  • ABC347G 题题解
    还算是比较经典了。首先我们注意到一个性质:\(1+3+\cdots+n=n^2\)。所以我们可以把平方拆开。然后容易证明\(a_{i,j}\)填\(1\)一定比填\(0\)不劣。我们可以把\(a_{i,j}\)拆成\(4\)个点,然后我们想到了最小割。构造网络:\(a_{i,j,x}\leftarrowa_{i,......
  • 三道dp的题解报告
    三道dp的题解报告圆题目来源牛客练习赛122D题练习赛链接https://ac.nowcoder.com/acm/contest/75768题面原题面为中文就直接放原题面截图了。解法事实上,把\(n\)与\(1\)断掉,断环为链,把原来的线段看成区间,线段相交就是区间之间部分覆盖(区间有重复部分但是没有相互包含关......
  • 题解:AT_abc176_e [ABC176E] Bomber
    分析我们可以用\(hf\)和\(wf\)分别储存每行的目标数及每列的目标数。然后我们可以贪心:若想摧毁最多的目标,则选定的位置所在的行是所有行中目标最多的,所在的列是所有列中目标最多的(感性理解一下)。但是,选定的位置也可能有一个目标。在统计摧毁的目标数时,该目标被算了两次......
  • P2143 [JSOI2010] 巨额奖金 题解
    P2143[JSOI2010]巨额奖金题解矩阵树定理+Kruskal最小生成树计数。思路MST都是喵喵题。引理1:所有合法的权值相同边的连边方案,得到的连通块情况是相同的。感性理解:如果不相同意味着至少有一条边可以连通一对连通块。所以我们可以这么做:先跑Kruskal标记树边,然后枚举......
  • P1967 [NOIP2013 提高组] 货车运输 题解
    P1967[NOIP2013提高组]货车运输原题地址思路:由于题目要求的是使两点之间的最小边权最大,所以可以构造最大生成树(最大生成树一定是最大瓶颈生成树,而瓶颈生成树上两点之间的路径,在原图中的所有路径中,最小边权仍然最大,即满足题目要求,详见https://oi-wiki.org/graph/mst/#性质),......
  • Golang | Leetcode Golang题解之第4题寻找两个正序数组的中位数
    题目:题解:funcfindMedianSortedArrays(nums1[]int,nums2[]int)float64{iflen(nums1)>len(nums2){returnfindMedianSortedArrays(nums2,nums1)}m,n:=len(nums1),len(nums2)left,right:=0,mmedian1,median2:=0,0......
  • CF1935D Exam in MAC 题解
    ExaminMAC题意\(t\)组数据。给定一个大小为\(n\)的集合\(s\)和一个整数\(c\),保证\(0\leqslants_i\leqslantc(1\leqslanti\leqslantn)\)。求有多少对整数数对\((x,y)\),满足:\(0\leqslantx\leqslanty\leqslantc\)。\(x+y\notins\)且\(y-x\not......
  • 2024最新一线互联网大厂常见高并发面试题解析
    面试官:临界区是什么?答:临界区用来表示一种公共资源或者说是共享资源,可以被多个线程使用。但是每一次,只能有一个线程使用它,一旦临界区资源被占用,其他线程要想使用这个资源,就必须等待。比如,在一个办公室里有一台打印机,打印机一次只能执行一个任务。如果小王和小明同时需要打......
  • 【赛题解析】【移动应用开发】全国职业院校技能大赛任务一:实现社区首页功能解析
    ​培训、环境、资料、考证公众号:波比网络公众号2:波比网络工作室移动应用开发技能大赛交流群:548238632波比网络专注于技能提升,赋能**本文章全文由波比网络原创,非法转载必究!**文章目录移动应用与开发任务1:实现社区首页功能1.界面顶部显示所在社区名称、轮播图和社......