A. Random Number Checker
奇数和偶数的数量之差小于1即为Good
B. Arithmetic Exercise
计算保留k位小数的a/b的结果
模拟除法即可,注意进位的细节
void solve() {
ll a, b , k;
cin >> a >> b >> k;
vector <int> ve(1, a/b);
ll c = a % b;
for (int i = 1; i <= k+1; i++) {
c *= 10;
ve.push_back(c / b);
c %= b;
}
if (ve[k+1] >= 5) {
ve[k]++;
}
for (int i = k; i > 0; i--) {
if (ve[k] >= 10) {
ve[k] %= 10;
ve[k-1]++;
} else break;
}
cout << ve[0] << '.';
for (int i = 1; i <= k; i++) {
cout << ve[i];
}
}
E. Great Detective TJC
找出给定的n个数中是否有一对异或值为1的两个数
方法一:排序后依次check相邻两数的异或值,时间复杂度O(nlogn)
方法二:把检查set里是否有当前数^1,然后把它插入set里,时间复杂度O(nlogn)
void solve() {
cin >> n;
set<int> st;
mark = 0;
for (int i = 0; i < n; i++) {
cin >> b;
if (st.count(b^1)) mark = 1;
st.insert(b);
}
if (mark) cout << "Yes\n";
else cout << "No\n";
}
G. Matrix Repair
给出一个部分残缺的01矩阵以及完好的该矩阵的每行每列的异或值,输出完整矩阵或-1
把行表示为0到n-1,列表示为n到2*n-1
给出的每行每列的异或值叫做res[i],每行每列已知的数的亦或和叫做xor[i]
易知当某一行 / 列仅剩一个未知数时可以用res[i] ^ xor[i]得到这个未知数的值
这个未知数解出来后可以继续去为它所在的那一列 / 行做贡献
可以用拓扑排序来考虑
即把每行 / 列作为一个点,未知数作为一条边连接它所在的行和列
度为1时可以求出这个未知数的值
如果拓扑排序结束后仍有边则说明有环无解
vector <vector <int> > ve, tu;
vector <int> d, xo, res;
void change(int a, int b) {
int c = xo[a] ^ res[a];
xo[b] ^= c;
if (a > b) swap(a, b);
b -= n;
tu[a][b] = c;
}
void solve() {
cin >> n;
queue<int> q;
ve = vector<vector<int> > (n<<1);
tu = vector<vector<int> > (n, vector<int> (n));
res = xo = d = vector<int> (n<<1);
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> tu[i][j];
if (tu[i][j] == -1) {
d[i]++;
d[n+j]++;
ve[i].push_back(n+j);
ve[n+j].push_back(i);
} else {
xo[i] ^= tu[i][j];
xo[n+j] ^= tu[i][j];
}
}
}
for (int i = 0; i < n*2; i++) cin >> res[i];
for (int i = 0; i < n*2; i++) {
if (d[i]) {
if (d[i] == 1) {
q.push(i);
}
}
}
while (q.size()) {
int now = q.front();
q.pop();
if (!d[now]) continue;
d[now] = 0;
for (int i : ve[now]) {
if (d[i]) {
d[i]--;
change(now, i);
if (d[i] == 1) q.push(i);
}
}
}
for (int i = 0; i < n*2; i++) {
if (d[i]) {
cout << "-1\n";
return;
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cout << tu[i][j] << (j == n-1 ? '\n' : ' ');
}
}
}
H. Visit the Park
给出一个图,输出按要求的节点顺序行走的权值的期望
注意两点之间可能会有多条边,存图需要特殊处理,笔者使用的是map<ll, vector<int> >
第一维存起点与终点的hash值(u<<30 | v),第二位存u->v的权值集合
然后按照给出的点的顺序遍历对应的vector即可
#define mk(a, b) (a<<30 | b)
unordered_map<ll, vector<int> > mp;
const int mod = 998244853;
int Power( ll x , int y ) {
ll res = 1;
while(y) {
if (y & 1) (res *= x) %= mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
ll ny (int now) {
return Power(now, mod-2);
}
void solve() {
cin >> n >> m >> k;
for (int i = 0; i < m; i++) {
cin >> a >> b >> c;
mp[mk(a, b)].push_back(c);
mp[mk(b, a)].push_back(c);
}
int now, nxt;
cin >> now;
ll ans = 0;
ll P10 = Power(10, k-2);
const ll ny10 = ny(10);
for (int i = 1; i < k; i++) {
cin >> nxt;
const ll NOW = mk(now, nxt);
if (!mp.count(NOW)) {
cout << "Stupid Msacywy!";
return;
}
int nynow = ny(mp[NOW].size());
for (int j : mp[NOW]) {
(ans += j * P10 % mod * nynow % mod) %= mod;
}
P10 = P10 * ny10 % mod;
now = nxt;
}
cout << ans << '\n';
}
I. Nim Game
对1e5数组询问 / 修改1e5次,修改是[l, r]加x,
询问是[l, r]的集合是否有一个可以使得nim博弈后手胜利(即异或和为0)的子集
修改可使用树状数组 / 线段树,单次操作时间复杂度为
由题知每个数的上界是2e9,由线性基可知不合法区间的最大长度为
所以若区间长度大于31就可以直接确定,否则可利用线性基求解,
单次操作时间复杂度为
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#ifdef LOCAL
template<class t,class u>ostream& operator<<(ostream& os,const pair<t,u>& p){return os<<"("<<p.first<<","<<p.second<<")";}
template<class t>ostream& operator<<(ostream& os,const vector<t>& v){os<<"{"; for(auto e:v)os<<e<<","; return os<<"}";}
#endif
int n, m, t, k, a, b, c, d, cnt, mark, an, oT_To, x, y, z, ans;
ll tree[100005];
int lowbit(int x) {
return x & (-x);
}
void update(int x, int val) {
for (; x < n; x += lowbit(x)) {
tree[x] += val;
}
}
ll ask(int x) {
ll res = 0;
for (; x; x -= lowbit(x)) {
res += tree[x];
}
return res;
}
vector <int> xx;
bool insert(int x) {
for (int i : xx) {
x = min(x, i ^ x);
}
if (!x) return 0;
for (int &i : xx) {
i = min(i, i ^ x);
}
xx.push_back(x);
return 1;
}
int main () {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> n >> m;
vector <int> ve (n+1);
for (int i = 1; i <= n; ++i) {
cin >> ve[i];
}
for (int i = 0; i < m; ++i) {
int op, l, r;
cin >> op >> l >> r;
switch (op) {
case 1:
cin >> x;
update(l, x), update(r + 1, -x);
break;
case 2:
if (r - l + 1 > 30) {
cout << "Yes\n";
} else {
xx.clear();
int i = l;
while (i <= r && insert(ve[i] + ask(i)) ) i++;
if (i > r) {
cout << "No\n";
} else cout << "Yes\n";
}
}
}
}
K. Bracket Sequence
求出n对k种合法的括号匹配序列的数量
易知n,1时结果为卡特兰数的第n项
每对括号都有k种可能性
故结果为 卡特兰数第n项
int main() {
cin >> n >> k;
cout << C(n*2, n) * ny(n+1) % mod * Power(k, n) % mod << '\n';
}
L. Suzuran Loves String
找出两个最长的前缀不同的后缀匹配
易知答案最小是len-1,此时字符串形如aaaaaa
找出第一个与str[0]不同的字符的下标i即可,两个后缀就是str和str+i
void solve() {
string s;
cin >> s;
ll ans = s.size() - 1;
for (int i = 1; i < s.size(); i++) {
if (s[i] != s[0]) {
ans = s.size() * 2 - i;
break;
}
}
cout << ans << '\n';
}
M. Sequence
输出
void solve() {
cin >> n;
vector <int> ve(n);
for (int i = 0; i < n; i++) {
cin >> ve[i];
}
cout << (ll)n * (*max_element(ve.begin(), ve.end()) - *min_element(ve.begin(), ve.end()));
}