2020 ICPC 沈阳站

牛客重现赛 Codeforces

C Mean Streets of Gadgetzan

Description

n 个命题, m 个事件作为命题可能的条件。命题有以下四种:

  1. x 表示x确定为真
  2. !x 表示x确定为假
  3. a1 a2 ... ak  -> x 表示:如果ai(i[1,k])都为真,则 x为真
  4. a1 a2 ...ak -> !x 表示:如果ai(i[1,k])都为真,则x为假

构造出m个条件的真假使得这 n 个命题不互相矛盾,并输出m个字符来表示m个条件的真假;

如果构造不出来,即 n 个命题互相矛盾,则输出“conflict”

Solution

注意到对于后面两个类型的命题,只要存在一个 ai 为假,则无论 x 取何值命题都为真。

初始将所有条件默认为0,标记为1 (为了区分原始赋的 0 和确定下来为 0 这两种情况)。

对于前面两个类型的命题,能够直接确定条件的真假,将值为 1 的条件加入队列 (注意至多进队一次);

对于后面两个类型的命题,用结构体 b 来记录信息,bnum 为当前命题记录在结构体中的编号(结构体的下标),vector<int>类型的 ind[t] 记录 t 作为 -> 前的一个ai 的命题编号,b 中存三个信息,①是命题包含的 ai 个数 num0(实际记录没有置为 1ai 数目,初始为 ai 总数目),②是命题中 -> 后的 x ,③是命题的类型 0 表示若 ai 都为真则 x 为真, 1 表示若 ai 都为真则 x 为假。

每次从队首取出一个元素 u,访问 ind[u] 所有的值,将命题对应的 num0 减一,若 num0==0 ,则其对应的 x 值可以确定下来,若 x 第一次被置为 1 ,则加入队列。

在操作的过程中出现任何矛盾都直接输出 conflict 并结束程序。

注:说明中的实现和程序并不完全一样,但意义和逻辑相同。

Code

//by DTTTTTTT
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<cstdio>
#include<vector>
#include<string>
#include<queue>
using namespace std;
const int N = 1e6 + 5;
int n, m, col[N], anum, a[N][2];
bool atype[N], vis[N];
vector<int> ind[N];
queue<int>q;
string s;
void END() {
	printf("conflict\n");
	exit(0);
}
int main() {
	cin >> n >> m;
	getchar();
	for (int i = 1;i <= m;++i) col[i] = -1;
	for (int i = 1;i <= n;++i) {
		getline(cin, s); //整行输入(不包括末尾换行符)
		if (s.find("->") == -1) {
			if (s[0] != '!') {
				int x = stoi(s);
				if (col[x] != -1) END();
				col[x] = 1;
				if(!vis[x]) q.push(x), vis[x]=1;
			}
			else {
				int x = stoi(s.substr(1));
				if (col[x] != -1) END();
				col[x] = 0;
			}
		}
		else {
			int pos = s.find("->"), anum_tmp = 0;
			++anum;
			string tmps = "";
			for (int j = 0;j < pos;++j)
				if (s[j] != ' ') tmps += s[j];
				else ind[stoi(tmps)].push_back(anum), tmps = "", ++anum_tmp;
			atype[anum] = (s[pos + 3] != '!');
			int x = stoi(s.substr(pos + 3 + (s[pos + 3] == '!')));
			a[anum][0] = x;
			a[anum][1] = anum_tmp;
		}
	}
	while (q.size()) {
		int u = q.front();q.pop();
		for (int i = 0;i < ind[u].size();++i) {
			int t = ind[u][i], x = a[t][0];
			--a[t][1];
			if (!a[t][1]) {
				if (atype[t]) {
					if (col[x] == 0) END();
					col[x] = 1;
					if (!vis[x]) q.push(x), vis[x] = 1;
				}
				else {
					if(col[x] == 1) END();
					col[x] = 0;
				}
			}
		}
	}
	for (int i = 1;i <= m;++i)
		if (col[i] == -1 || col[i] == 0) printf("F");
		else printf("T");
	return 0;
}

D-Journey to Un'Goro

Description

​ 构造一个长度为 n 的序列,其组成元素只能是 br ,区间 [i,j] 是一段“好”的区间当且仅当该区间内的 r 有奇数个。

​ 首先输出长度为 n 的序列最多有多少个 “好” 的区间,然后按照字典序输出“好”的区间数最多的序列,若这样的序列超过100个,则只需输出按字典序排序后的前100个。

Solution

​ 容易想到,当序列元素全为 r 时,达到最大答案:

​ 若 n 为奇数,ans=n+(n2)+(n4)+...+1=(n+1)24

​ 若 n 为偶数,ans=n+(n2)+(n4)+...+2=n(n+2)4

​ 由于最小只需要输出100个序列,考虑搜索+剪枝。

​ 尝试多找到一些性质来剪枝。

​ 设S[i]表示序列的前i个元素中r的个数,则一个区间[i,j]好,当且仅当S[j]S[i1]为奇数 S[j]S[i1]的奇偶性不同。

​ 若S[1]...S[n]中共有X个奇数,Y个偶数,则答案为XYXY=X(nX)=X2+nX=(Xn2)2+n24

​ 当且仅当X==Y|XY|==1时,XY取得最大值。

Code

//by DTTTTTTT
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#define ll long long
using namespace std;
const int N = 1e5 + 5;
int n, totr[2], totbr[2], totans, maxr;
ll ans;
char seq[N];
void dfs(int cur, int totr1, int totr2, bool flag) {  
	//totr1  前缀r数目为奇数的个数 totr2 前缀r数目为偶数的个数 flag=0 当前前缀r数目为偶 flag=1 当前前缀r数目为奇
	if (totr1 > maxr || totr2 > maxr) return;
	if (cur == n) {
		++totans;
		seq[n] = '\0';
		printf("%s\n", seq);
		if (totans == 100) exit(0);
		return;
	}

	seq[cur] = 'b';
	dfs(cur + 1, totr1 + flag, totr2 + (flag ^ 1), flag);  //注意(flag^1)处要打括号

	seq[cur] = 'r';
	dfs(cur + 1, totr1 + (flag ^ 1), totr2 + flag, flag ^ 1);

}
int main() {
	cin >> n;
	if (n % 2) ans = 1ll * (n + 1) * (n + 1) / 4;
	else ans = 1ll * n * (n + 2) / 4;
	cout << ans << endl;
	maxr = (n + 2) / 2;
	dfs(0, 0, 1, 0);
	return 0;
}

F Kobolds and Catacombs 思维

Description

What's the maximum number of consecutive groups they can be partitioned into, such that after reordering the kobolds in each group in non-descending order, the entire queue is non-descending?

给定一个序列,问该序列最多能划分为多少个区间,满足:对每个区间内排序后,整个序列是不下降的。

Solution

思路:将序列排序,比较、观察原序列(a)与排序后序列(b)。

注意到对于下标 i ,若 a 数组与 b 数组的前 i 个数相同, 就在 i 后面将序列划开。可以得到最大区间数目。

思考用什么特征值来判断前 i 个数是否相同。

可以证明 前缀和可以作为这个特征值。

简单证一下:

假设前缀和不足以作为该特征值,即  sumai=sumbi{a1,..,ai}{b1,...,bi}

i=2时,

a1+a2=b1+b2{a1,a2}{b1,b2}

假设a1<a2,则一定有 b1<a1<b2<a2 or a1<b1<a2<b2,那么对 a 序列排序后,b1,b2 之间一定还有一个$a_1 a_2$ 。则假设不成立。

i>2的情况类似。

Code

//by DTTTTTTT
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
int n, a[N], b[N], ans;
ll suma[N], sumb[N];
int main() {
	cin >> n;
	for (int i = 1;i <= n;++i) cin >> a[i], b[i]=a[i];
	sort(b + 1, b + n + 1);
	for (int i = 1;i <= n;++i) {
		suma[i] = suma[i - 1] + a[i];
		sumb[i] = sumb[i - 1] + b[i];
		if (suma[i] == sumb[i]) ++ans;
	}
	cout << ans << endl;
	return 0;
}

G The Witchwood 签到题

Description

n 个物品,第 i 个物品价值 ai ,最多取 k 个物品,求最大价值。

Solution

签到题。 对所有 ai 从大到小排序,取前 k 个加起来就是答案。

H The Boomsday Project DP+二分

Description

n 种优惠券,第 i 种优惠券的有效时间为 d[i] 天,可以免费借用 k[i] 次自行车,价格为 c[i]

Aloha 会借用自行车 m 天,在第 p[i] 天,他会借用 q[i] 次自行车。

如果不使用优惠券,单次借用自行车的价格为 r 元。

Aloha 的最小费用。

Solution

长得就像动态规划的样子?

f[i] 为前 i 次借用自行车的最小花费。

外层循环枚举前 i 次借用,内层循环枚举第 j 种优惠券。

转移:找到 ind 满足:第 ind+1...i 次借用都可以使用当前枚举的第 j 种优惠券

f[i]=min(f[i],f[ind]+c[j])

初始条件:f[0]=0 f[i]=inf(i=1,2,...,q[i])

细节还是挺多的,,以及,,重构代码解决 dtt 99%的问题!

Code

//by DTTTTTTT
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 505, M = 1e5 + 5, Q = 3e5 + 5;
const ll inf = 1e18;
int n, m, r, d[N], k[N], c[N], sumq[M], totq, days[Q];
ll f[Q];
struct days {
	int p, q;
}a[M];
bool cmp(struct days x, struct days y) {
	return x.p < y.p;
}
int ef(int cur, int limit) {
	int l = 1, r = m, mid, ret = 1;
	while (l <= r) {
		mid = (l + r) >> 1;
		if (a[mid].p >= cur - limit + 1) ret = mid, r = mid - 1;
		else l = mid + 1;
	}
	return ret;
}
int main() {
	scanf("%d%d%d", &n, &m, &r);  //n种优惠券 m天 单次借用花费r元
	for (int i = 1;i <= n;++i) scanf("%d%d%d", &d[i], &k[i], &c[i]); //d:天数限制 k:次数限制 c:价格
	for (int i = 1;i <= m;++i) scanf("%d%d", &a[i].p, &a[i].q); //第p天借用q次

	sort(a + 1, a + m + 1, cmp);
	for (int i = 1;i <= m;++i) {
		sumq[i] = sumq[i - 1] + a[i].q;
		for (int j = 1;j <= a[i].q;++j) {
			int cur = sumq[i - 1] + j;
			f[cur] = inf;
			days[cur] = a[i].p;
		}
	}
	totq = sumq[m];
	d[0] = k[0] = 1, c[0] = r;

	for (int i = 1;i <= totq;++i) {
		for (int j = 0;j <= n;++j) {
			int ind;
			if (days[max(i - k[j] + 1, 1)] >= days[i] - d[j] + 1) ind = max(i - k[j], 0);
			else ind = sumq[ef(days[i], d[j]) - 1];
			f[i] = min(f[i], f[ind] + c[j]);
		}
	}
	printf("%lld\n", f[totq]);
	return 0;
}

I Rise of Shadows 数学/同余

Description

Azeroth 的时间设置如下:一天 H 个小时,一小时 M 分钟。

给定一个Azeroth的时钟,问一天之内有多少整数分钟时刻满足个分针和时针夹角不超过 αα=2π×AH×M)。

已知新的一天开始时,时针和分针重合。

Solution

时针的每分钟旋转的角度: 2πH×M

分针每分钟旋转的角度:2πM

计入答案的整数分钟时刻 t 应该满足:

2πkα(2πM2πH×M)×t2πk+α  (k=0,1,...)

H×M×kα×H×M2π(H1)×tH×M×k+α×H×M2π  (k=0,1,...)

α=2π×AH×M

H×M×kA(H1)×tH×M×k+A  (k=0,1,...)

(H1)×tA (mod HM)(H1)×tHMA (mod HM)

等价于 (H1)×tK(mod HM) 其中 KAKHMA

线性同余方程 axb(mod m) 有解当且仅当 gcd(a,m)|b

在有解时,先用欧几里得算法求出一组整数x0,y0,满足 ax0+my0=gcd(a,m),则x=x0b/gcd(a,m)是该线性方程的一个解。

Bezout定理可知:gcd(a,m)=1时,axb(mod m)x[0,m1] 上有唯一解。

同样地,a/gcd(a,m)m/gcd(a,m)互质,则agcd(a,m)xbgcd(a,m) (mod mgcd(a,m))x[0,mgcd(a,m)1]上有唯一解。

为了满足gcd(a,m)=1,将等式(H1)×tK(mod HM) 其中 KAKHMA 两边同时除以gcd(H1,HM)得:

H1gcd(H1,HM)×tKgcd(H1,HM)(mod HMgcd(H1,HM))

Bezout定理可知:由于H1gcd(H1,HM)HMgcd(H1,HM)互质,H1gcd(H1,HM)×tKgcd(H1,HM)(mod HMgcd(H1,HM))x[0,HMgcd(H1,HM)1]上有唯一解,在x[HMgcd(H1,HM),2HMgcd(H1,HM)1]上有唯一解..........

H1gcd(H1,HM)×tKgcd(H1,HM)(mod HMgcd(H1,HM))[0,HM1]上有gcd(H1,HM)个解。

即:对于每一个有解的K (即:满足 gcd(H1,HM)|K),有gcd(H1,HM)个合法的t

而有解的K的数目为:(Agcd(H1,HM)+1)+(HMgcd(H1,HM)HMAgcd(H1,HM))

所以答案为:

(Agcd(H1,HM)+1)+(HMgcd(H1,HM)HMAgcd(H1,HM))gcd(H1,HM)

注意到当A=HM2 时,A=HMA,按照 KAKHMA 求得K的数目可能会多一个,需要特殊判断,易知这种情况的答案为HM

Code

//by DTTTTTTT
#include<iostream>
#define ll long long
using namespace std;
ll H, M, A;
ll gcd(ll x, ll y) {
	return y == 0 ? x : gcd(y, x % y);
}
int main() {
	cin >> H >> M >> A;
	if (A * 2 == H * M) {
		cout << A * 2 << endl;
		return 0;
	}
	ll d = gcd(H - 1, H * M);
	cout << d * (A / d + 1 + H * M / d - (H * M - A + d - 1) / d) << endl;
	return 0;
}

K Scholomance Academy

Description

posted @   DTTTTTTT-  阅读(157)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示