AGC030 简要题解
A - Poisonous Cookies
题意
- 有\(A\)个能解毒的普通饼干,\(B\)个能解毒的美味饼干,\(C\)个有毒的美味饼干,求最多能吃多少个美味饼干,每次吃完有毒的饼干后要解毒后才能继续吃。
 
题解
输出\(\text{min(A + B + 1, C) + B}\)即可。
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
	int a, b, c; 
	cin >> a >> b >> c;
	printf("%d\n", min(a + b + 1, c) + b);
	return 0;
}
B - Tree Burning
题意
- 在一个长为\(L\)的环上有\(n\)个关键点,求访问完所有关键点走的路径长度最大值。
 
题解
可以发现最优解一定是先往一个方向走,然后每次变换方向,那么枚举往一个方向走到第几个点,取最大值即可。
代码
#include <bits/stdc++.h>
using namespace std; 
const int N = 2e5 + 9;
ll n, L, ans, a[N], b[N], Sa[N], Sb[N];
ll Qa(int l, int r) { return Sa[r] - Sa[l - 1]; }
ll Qb(int l, int r) { return Sb[r] - Sb[l - 1]; }
void Solve() {
	for (int i = n; i; -- i) {
		int blen = (n - i) >> 1, alen = n - i - blen;
		chkmax(ans, ((n - i) & 1 ? b[n - blen] : a[n - alen]) + (Qb(n - blen + 1, n) + Qa(i, i + alen - 1)) * 2);
	}
}
int main() {
	scanf("%d%d", &L, &n);
	for (int i = 1; i <= n; ++ i)
		scanf("%d", &a[i]);
	for (int i = 1; i <= n; ++ i) {
		b[i] = L - a[i];
		Sa[i] = Sa[i - 1] + a[i];
		Sb[i] = Sb[i - 1] + b[i];
	}
	Solve();
	for (int i = 1; i <= n; ++ i)
		a[i] = b[n - i + 1];
	for (int i = 1; i <= n; ++ i) {
		b[i] = L - a[i];
		Sa[i] = Sa[i - 1] + a[i];
		Sb[i] = Sb[i - 1] + b[i];
	}
	Solve();
	cout << ans << endl;
	return 0;
}
C - Coloring Torus
题意
- 构造一个\(\text{n × n}\)的矩阵,满足其中出现了\(k\)种数,对于每种数出现的每个位置,满足这些位置上下左右出现的每种数的个数相同,\(k\le10^3,n\le500\)。
 
题解
首先\(k\le500\)的很好填,直接\(n = k\),每行都一样填满所有颜色即可。
如果\(k>500\),我们令\(n = 2\lceil \frac k 4\rceil\),我们有个很直观的想法就是每个位置\((x,y)\)填\(\text{(x + y) mod n + 1}\),这个东西满足题意应该很显然,但是颜色数可能不够,我们把偶数行拿出来,让偶数行填\(\text{(x + y) mod n + n + 1}\),如果大于\(\text{k}\)就不加\(\text n\),想一下这样为什么是对的,可以加\(\text{n}\)的位置一定是一行连续的数,那么对于奇数行的一个数,加\(\rm{n}\)的位置一定一个在下方一个在上方,左右的数是不会加的,而对于偶数行加的位置一个在左边一个在右边,上下的数是不会加的,这样就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
int a[501][501];
int main() {
	int k;
	scanf("%d", &k);
	if (k <= 500) {
		cout << k << endl;
		for (int i = 1; i <= k; ++ i)
			for (int j = 1; j <= k; ++ j)
				printf("%d%c", i, j == k ? '\n' : ' ' );
		return 0;
	}
	int n = ((k + 3) / 4) << 1;
	cout << n << endl;
	for (int i = 1; i <= n; ++ i)
		for (int j = 1; j <= n; ++ j) {
			a[i][j] = (i + j) % n + (i & 1 ? 0 : n) + 1;
			if (a[i][j] > k) a[i][j] -= n;
			printf("%d%c", a[i][j], j == n ? '\n' : ' ');
		}
	return 0;
}
D - Inversion Sum
题意
- 给你一个长为\(n\)的数列,\(q\)个交换两个位置的数的操作,对于每个操作是否执行所有\(2^q\)种情况的逆序对数的和。
 
题解
我们可以计算\(q\)轮操作后的期望逆序对数,乘上\(2^q\)即可,那么就很简单了,设\(\rm{dp[i][j][k]}\)为\(i\)轮操作后\(j<k\)的概率,那么每次操作只会修改\(O(n)\)个\(\rm{DP}\)值,复杂度\(O(n^2+nq)\)。
代码
#include <bits/stdc++.h>
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 3000 + 3;
const int mod = 1e9 + 7;
int qpow(int a, int x) {
	int ret = 1;
	while (x) {
		if (x & 1) ret = ret * (ll)a % mod;
		x >>= 1, a = a * (ll)a % mod;
	}
	return ret;
}
int f[N][N], a[N], ans;
int main() {
	int n, q, x, y;
	scanf("%d%d", &n, &q);
	For(i, 1, n) scanf("%d", &a[i]);
	For(i, 1, n) For(j, 1, n) f[i][j] = a[i] < a[j];
	For(cas, 1, q) {
		read(x), read(y);
		f[x][y] = f[y][x] = 500000004ll * (f[x][y] + f[y][x]) % mod;
		For(i, 1, n) if (i ^ x && i ^ y) {
			f[x][i] = f[y][i] = 500000004ll * (f[x][i] + f[y][i]) % mod;
			f[i][x] = f[i][y] = 500000004ll * (f[i][x] + f[i][y]) % mod;
		}
	}
	For(i, 1, n) For(j, i + 1, n) (ans += f[j][i]) %= mod;
	cout << 1ll * ans * qpow(2, q) % mod << endl;
	return 0;
}
E - Less than 3
题意
- 给你两个\(01\)串\(\rm{S, T}\),每次可以把一位取反,求\(\rm{S-T}\)的最小操作次数,同时需要保证操作过程种不会出现连续的三个字符。
 
题解
这个东西不太好做,考虑转换模型,我们在\(01\)之间加一块红色的隔板,\(10\)间加一块蓝色的隔板,同时串首尾都有无穷多块隔板。
那么我们发现每次取反一个位置相当于把隔板移动了一格,同时隔板间是不能跨越的,隔板匹配的一个方案对应着一个合法的操作方案。
如果已经知道了隔板位置的话,因为隔板不能跨越,我们知道操作次数的下界是每对对应隔板的坐标差,同时我们可以构造一种方法达到这个下界,大概就是每次要移动隔板的时候移动中间一段连续的两边的都不动,所以可以\(O(n)\)求出操作次数,那么直接枚举\(\rm S\)串前有多少个隔板,取最小值即可,复杂度\(O(n^2)\)。
代码
#include <bits/stdc++.h>
#define mp make_pair
#define For(i, a, b) for (int i = a; i <= b; ++ i)
using namespace std;
const int N = 5e3 + 7;
pair<int, int> a[N], b[N];
char s[N], t[N];
int n, ans = inf, c, d;
void Solve() {
	For(i, 0, n) {
		if ((a[1].y + b[1].y + i) & 1) continue;
		int res = 0, now = 1;
		while (now <= c) {
			int ps = a[now].x, pt = now + i <= d ? b[now + i].x : n + 1;
			res += abs(pt - ps), ++ now;
		}
		while (now + i <= d) res += n + 1 - b[now + i].x, ++ now;
		For(j, 1, i) {
			int pt = j <= d ? b[j].x : n + 1;
			res += pt - 1;
		}
		chkmin(ans, res);
	}
}
int main() {
	scanf("%d%s%s", &n, s + 1, t + 1);
	For(i, 1, n) {
		if (s[i] != s[i - 1])
			a[++ c] = mp(i, s[i] ^ 48);
		if (t[i] != t[i - 1])
			b[++ d] = mp(i, t[i] ^ 48);
	}
	Solve(), swap(c, d), swap(a, b), Solve();
	printf("%d\n", ans);
	return 0;
}
F - Permutation and Minimum
题意
- 给你一个长为\(2n\)的排列\(a\),\(a\)的有些位置还没有填数,定义序列\(b\)满足\(b[i]=\min(a[2i],a[2i-1])\),求有多少种不同的序列\(a\)。
 
题解
先考虑\(a\)序列什么都没填的情况,我们可以先不考虑顺序,那么方案数就是长度为\(2n\)的括号序列数乘上\(n!\),这启示我们往括号序列的方向上思考。
我们把\(2n\)个数分类,有的已经确定了就不用管,而没有确定的就只有相邻数没填或者两个数都没填的,我们分别记为特殊括号和普通括号。设\(f(i,j,k)\)表示\([i,2n]\)的数已经确定,其中还有\(j\)个特殊括号,\(k\)个普通括号没有匹配的方案数,我们每次考虑当前这个数作为左括号还是右括号。特别地如果当前这个数是普通左括号要匹配一个普通右括号时,先把方案数记作\(1\),也就是先不分配位置,最后若有\(m\)对普通括号匹配了,他们的位置可以任意排,所以还要乘个\(m!\),复杂度\(O(n^3)\)。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 300 + 7;
const int mod = 1e9 + 7;
int n, cnt;
int f[N << 1][N][N];
int a[N << 1], b[N << 1];
int main() { 
	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		int y = i << 1, x = y - 1;
		scanf("%d%d", &a[x], &a[y]);
		if (a[x] ^ -1) {
			if (a[y] == -1) b[a[x]] = -1;
			else b[a[x]] = b[a[y]] = 1;
		} else {
			if (a[y] ^ -1) b[a[y]] = -1;
			else ++ cnt;
		}
	}
	// f[i][j][k] [i, 2n] is ok, j special ), k normal )。
	f[n << 1 | 1][0][0] = 1;
	for (int i = n << 1; i; -- i) {
		if (b[i] == 1) memcpy(f[i], f[i + 1], sizeof(f[i]));
		else {
			for (int j = 0; j <= n; ++ j)
				for (int k = 0; k <= n; ++ k) {
					if (b[i] ^ -1) {
						(f[i][j][k + 1] += f[i + 1][j][k]) %= mod;
						if (j) (f[i][j - 1][k] += 1ll * j * f[i + 1][j][k] % mod) %= mod;
						if (k) (f[i][j][k - 1] += f[i + 1][j][k] % mod) %= mod;
					} else {
						(f[i][j + 1][k] += f[i + 1][j][k]) %= mod;
						if (k) (f[i][j][k - 1] += f[i + 1][j][k]) %= mod;
					}
				}
		}
	}
	for (int i = 1; i <= cnt; ++ i)
		f[1][0][0] = 1ll * f[1][0][0] * i % mod;
	printf("%d\n", f[1][0][0]);
	return 0;
}
												
											AGC030 简要题解的更多相关文章
- Noip 2014酱油记+简要题解
		
好吧,day2T1把d默认为1也是醉了,现在只能期待数据弱然后怒卡一等线吧QAQ Day0 第一次下午出发啊真是不错,才2小时左右就到了233,在车上把sao和fate补掉就到了= = 然后到宾馆之后 ...
 - Tsinghua 2018 DSA PA2简要题解
		
反正没时间写,先把简要题解(嘴巴A题)都给他写了记录一下. upd:任务倒是完成了,我也自闭了. CST2018 2-1 Meteorites: 乘法版的石子合并,堆 + 高精度. 写起来有点烦貌似. ...
 - Codeforces 863 简要题解
		
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 简要题解?因为最后一题太毒不想写了所以其实是部分题解... A题 传送门 题意简述:给你一个数,问你能不能通过加前导000使其成为一个回文数 ...
 - HNOI2018简要题解
		
HNOI2018简要题解 D1T1 寻宝游戏 题意 某大学每年都会有一次 Mystery Hunt 的活动,玩家需要根据设置的线索解谜,找到宝藏的位置,前一年获胜的队伍可以获得这一年出题的机会. 作为 ...
 - JXOI2018简要题解
		
JXOI2018简要题解 T1 排序问题 题意 九条可怜是一个热爱思考的女孩子. 九条可怜最近正在研究各种排序的性质,她发现了一种很有趣的排序方法: Gobo sort ! Gobo sort 的算法 ...
 - BJOI2018简要题解
		
BJOI2018简要题解 D1T1 二进制 题意 pupil 发现对于一个十进制数,无论怎么将其的数字重新排列,均不影响其是不是 \(3\) 的倍数.他想研究对于二进制,是否也有类似的性质. 于是他生 ...
 - CQOI2018简要题解
		
CQOI2018简要题解 D1T1 破解 D-H 协议 题意 Diffie-Hellman 密钥交换协议是一种简单有效的密钥交换方法.它可以让通讯双方在没有事先约定密钥(密码)的情况下,通过不安全的信 ...
 - AtCoder ExaWizards 2019 简要题解
		
AtCoder ExaWizards 2019 简要题解 Tags:题解 link:https://atcoder.jp/contests/exawizards2019 很水的一场ARC啊,随随便便就 ...
 - Comet OJ - Contest #2 简要题解
		
Comet OJ - Contest #2 简要题解 cometoj A 模拟,复杂度是对数级的. code B 易知\(p\in[l,r]\),且最终的利润关于\(p\)的表达式为\(\frac{( ...
 
随机推荐
- c++入门之类与内存
			
类作为c++编程的核心,自然我们十分关注其内存分配问题. 这里的这个主题中,我们关注了静态成员,new,delete.还有构造函数和析构函数. 先上代码: # include "iostre ...
 - jmeter分布式压测(多台电脑一起压测)
			
(1)在Windows下运行 操作步骤: 1) 有多台电脑,每台电脑上都有jmeter,而且这几台电脑都互相能ping通. 2) 在我的电脑的jmeter的配置文件bin目录下的jme ...
 - semantic-ui 输入框
			
1.标准输入框 semantic-ui中定义输入框需要将input标签包含于另外一个标签内,外层标签的class为ui input,注意外层标签可以是div,span.p.i. <div cla ...
 - asp.net mvc area实现多级controller和多级view
			
经常需要描述这样的项目结构 ~:. //web根目录├─.admin //管理员功能目录│ └─index.html //管理员目录页面├─.user / ...
 - laravel服务容器
			
laravel框架底层解析 本文参考陈昊<Laravel框架关键技术解析>,搭建一个属于自己的简化版服务容器.其中涉及到反射.自动加载,还是需要去了解一下. laravel服务容器 建立项 ...
 - Mybatis Dao层注解及XML组合Dao的开发方式
			
mybatis可以用xml进行数据操作,也可以在dao层用注解的方式,也可以采取xml和dao层接口组合使用的方法.显然 ,后者更加简单. 实体类Student package com.zhao. ...
 - CLOUD SQL跟踪
			
CLOUD会自动在后台执行一些sql语句,所以追踪起来比较麻烦,需要加入一些过滤条件. 比如关键的CLIENTPROCESSID,加入后 ,就能过滤是哪个客户度执行的数据. 过滤数据.
 - java中级——集合框架【1】-ArrayList
			
集合框架----ArrayList 引子:我们先来看看传统数组的用法 写一个Hero对象类 package cn.jse.t1; public class Hero { public String n ...
 - LODOP打印超文本中部分文字消失的一种情况1
			
如果有两对空span,第一对里面是空格,第二对里面是文字,在这两对span标签之间的文字会消失. <span> </span>文字<span>文字</span ...
 - solr +IKAnalyzer2012FF_u1 功能图