UESTC - 第12届 ACM 趣味赛二

A

分享一个自己踩到的坑点,以下代码会 \(RE\)

#include <iostream>
#include <string>
using namespace std;
const string TEXT = "NicoNicoNi";

string str;
int ans;

int main(){
	cin >> str;
	for(int i = 0; i < str.length() - TEXT.length(); i++)
		if(str.substr(i, TEXT.length()) == TEXT) ans++;
	cout << TEXT << " * " << ans;
	return 0;
}

原因自行悟道\(.jpg\)

B

\(sum=\sum a_i\),再设给 \(Y\) 加上 \(x\),则给 \(X\) 减去 \((sum-x)\),那么最后的答案是 \((Y+x)^2-(X-sum+x)^2=(Y+X-sum+2x)(Y-X+sum)\)

显然 \((Y-X+sum)\) 是个常数,因此当 \((Y-X+sum)\) 为正数时最大化 \((Y+X-sum+2x)\),当为负数时最小化 \((Y+X-sum+2x)\),当 \((Y-X+sum)\)\(0\) 时答案恒为 \(0\)

因此做法就是:当 \(Y-X+sum>0\) 时,把 \(a_i\) 全部加给 \(Y\);当 \(Y-X+sum<0\) 时,将 \(a_i\) 全部减给 \(X\)

C

我们可以看出来 \(a_i\) 的贡献要么是 \(+a_i\) 要么是 \(-a_i\),因此我们要考虑 \(a_i\) 分别落入这两种情况的概率,而很显然这个概率只与 \(a_i\) 之前的数的被删除顺序有关。设 \(f_i\) 表示第 \(i\) 个数贡献为正的概率,则求解 \(f_i\) 时分为两种情况:

  • 第一次操作数 \(<i-1\),即被删除的数是 \(a_i\) 之前的数。由于删去了一个数,则此时 \(a_i\) 之前的数的个数(包括它本身)变为 \((i-1)\),这样的话 \(a_i\) 贡献为正的概率就是 \(f_{i-1}\)。而落入这种情况的概率是 \(\frac{i-2}{i-1}\),因此在这种情况下 \(a_i\) 贡献为正的总概率为 \(\frac{i-2}{i-1}×f_{i-1}\)
  • 第一次操作数 \(=i-1\),即被删除的数正好是 \(a_i\)。此时 \(a_{i-1}\) 变为 \(a_{i-1}-a_i\),因此若要 \(a_i\) 的贡献为正,则 \(a_{i-1}\) 的贡献需要为负,因此这种情况下 \(a_i\) 贡献为正的概率是 \(1-f_{i-1}\)。而落入这种情况的概率是 \(\frac1{i-1}\),因此在这种情况下 \(a_i\) 贡献为正的总概率为 \(\frac1{i-1}×(1-f_{i-1})\)

由此我们可以得到递推方程:\(f_i=\frac{i-2}{i-1}×f_{i-1}+\frac1{i-1}×(1-f_{i-1})\)。最后计算出 \(\sum f_i×a_i-(1-f_i)×a_i\) 即为答案。

D

约定 \(r\) 表示行数,\(c\) 表示列数。那么分为两种情况:

  • \(r_{A_1}\neq c_{A_n}\)。此时对于 \(\forall x\) \((x\neq r_{A_1}\)\(x\neq c_{A_n})\)\(x\) 作为任意矩阵的 \(r\) 的次数一定等于 \(x\) 作为任意矩阵的 \(c\) 的次数。而 \(r_{A_1}\) 作为任意矩阵的 \(r\) 的次数一定比它作为任意矩阵的 \(c\) 的次数多 \(1\)\(c_{A_n}\) 同理。
  • \(r_{A_1}=c_{A_n}\)。此时对于 \(\forall x\)\(x\) 作为任意矩阵的 \(r\) 的次数一定等于 \(x\) 作为任意矩阵的 \(c\) 的次数,不存在特例。

因此我们需要判断给出的数据属于这两种情况的哪一种。判断方法是,如果 \(\exists x\) 使得其作为 \(r\) 的次数不等于其作为 \(c\) 的次数,则属于情况 \(1\);否则,属于情况 \(2\)

对于情况 \(1\),一定存在且仅存在两个数 \(x\)\(y\) 属于特例。输出 \(x×y\) 即可。

对于情况 \(2\),输出最大的数的平方即可。

E

\(n=len(S)\)\(S\) 翻转后的结果为 \(T\),称 \(S\)\(T\) 为单位串,则我们得到的字串为 \(STTSTSSTTSSTSTTS...\)

因此,我们首先要知道题目要求的第 \(k\)\(bit\) 属于第几个单位串中。设第 \(k\)\(bit\) 属于第 \(x\) 个单位串,那么显然 \(x=\lceil\frac nk\rceil\)。那么我们需要确定第 \(x\) 个单位串是 \(S\) 还是 \(T\)

我们可以每次将 \(x\) 折半。设 \(i\) 为满足 \(2^i<x\) 的最大的 \(i\),则第 \((2^i+1)\sim (2^i+2^i)\) 个单位串是第 \(1\sim 2^i\) 个单位串取反。因此我们令 \(x-=2^i\),然后将取反标记 \(inv\hat{}=1\),初始时 \(inv=0\)。当 \(x\) 减为 \(1\) 时,若 \(inv==0\),则第 \(x\) 个串为 \(S\);否则第 \(x\) 个串为 \(T\)

Code

#include <cstdio>
using namespace std;
const int N = 1e5 + 1;

int n, bit;
unsigned long long x, y, k;
char s[N + 1];

int main(){
	scanf("%d%llu%s", &n, &k, s + 1);
	x = (k - 1) / n + 1;
	y = k - (x - 1) * n;
	while(x > 1){
		int i = 0;
		while((1ull << i) < x) i++;
		x -= (1ull << --i);
		bit ^= 1;
	}
	putchar(s[y] ^ bit);
	return 0;
}
posted @ 2021-11-27 16:03  SpaceJellyfish  阅读(122)  评论(0编辑  收藏  举报