目录
B. Binary Vector
https://ac.nowcoder.com/acm/contest/5671/B
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int M = 2e7;
int n;
ll qpow(ll a, ll b) {
a %= mod;
ll res = 1;
while (b) {
if (b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
ll res[M + 5];
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll x = 1, y, z = 1, tmp = 1;
ll Inv2 = qpow(2, mod - 2);
res[0] = 0;
for (int i = 1; i <= M; i++) {
x = (x * 2) % mod;
y = x - 1;
z = (z * Inv2) % mod;
tmp = (tmp * (y * z % mod)) % mod;
res[i] = res[i - 1] ^ tmp;
}
int T;
cin >> T;
while (T--) {
cin >> n;
cout << res[n] << endl;
}
return 0;
}
C. Combination of Physics and Maths
https://ac.nowcoder.com/acm/contest/5671/C
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e3 + 10;
ll a[N][N];
int n, m;
ll sum[N][N];
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%lld", &a[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
sum[i][j] = sum[i - 1][j] + a[i][j];
double ans = 0.0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
ans = max(ans, (1.0 * sum[i][j]) / (a[i][j] * 1.0));
printf("%.8f\n", ans);
}
return 0;
}
E. Easy Construction
https://ac.nowcoder.com/acm/contest/5671/E
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int n, k;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> k;
if (n & 1) {//奇数
if (k != 0) {
puts("-1");
return 0;
} else {
a[1] = n;
for (int i = 2, j = 1; i <= n; i += 2, j++) {
a[i] = j;
a[i + 1] = n - j;
}
}
} else {//n 偶数
int tmp = (1 + n) * n / 2;
if ((tmp % n) != k) {
puts("-1");
return 0;
} else {
a[1] = n;
a[2] = n / 2;
for (int i = 3, j = 1; i <= n; i += 2, j++) {
a[i] = j;
a[i + 1] = n - j;
}
}
}
for (int i = 1; i <= n; i++) {
cout << a[i] << ' ';
}
return 0;
}
G. Grid Coloring
https://ac.nowcoder.com/acm/contest/5671/G
#include <bits/stdc++.h>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n, k;
scanf("%d%d", &n, &k);
if (n == 1 || k == 1 || (n + 1) * 2 * n % k != 0) {
puts("-1");
} else {
int p = 0;
for (int i = 1; i <= 2 * (n + 1); i++) {
for (int j = 1; j <= n; j++) {
p = (p + 1) % k;
printf("%d ", p + 1);
}
if (n % k == 0)p = (p + 1) % k;
printf("\n");
}
}
}
return 0;
}
H. Harmony Pairs · 数位dp
https://ac.nowcoder.com/acm/contest/5671/H
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 1e3 + 10;
int sz;
int num[105];
ll dp[105][N * 2][2][2]; // dp[pos][sum][limB][limA]
// pos 当前位置
// sum B-A在前pos位上的差值总和
// limB limA B、A在当前位置枚举到的数位的限制 即 当前位是否可以枚举到数字9 0-不受限制 1-限制
ll dfs(int pos, int sum, int limB, int limA) {
if (pos == sz) return sum > N ? 1 : 0;//为防止sum出现负数 在一开始时加上一个基础值
if (~dp[pos][sum][limB][limA]) return dp[pos][sum][limB][limA];
int upB = limB ? num[pos] : 9;
ll res = 0;
for (int i = 0; i <= upB; i++) {
int upA = limA ? i : 9;// 题目要求 B>=A 且 S(A) > S(B)
for (int j = 0; j <= upA; j++) {
res = (res + dfs(pos + 1, sum + (j - i), limB && i == upB, limA && j == upA)) % mod;
}
}
return dp[pos][sum][limB][limA] = res;
}
ll solve(string s) {
sz = s.length();
for (int i = 0; i < sz; i++) {
num[i] = s[i] - '0';
}
// 从最高位开始
return dfs(0, N, 1, 1);
}
string s;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(dp, -1, sizeof dp);
cin >> s;
cout << solve(s) << endl;
return 0;
}
J. Josephus Transform · 线段树 + 置换
https://ac.nowcoder.com/acm/contest/5671/J
官方题解
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int a[N];
int n, m, k, x;
int p[N], nxt[N];
struct segTree {
#define ls (o<<1)
#define rs (o<<1|1)
struct node {
int l, r;
int sum;
} t[N << 2];
void pushup(int o) {
t[o].sum = t[ls].sum + t[rs].sum;
}
//不带数组 建树
void build(int o, int l, int r) {
t[o].l = l;
t[o].r = r;
if (l == r) {
t[o].sum = 1;
return;
}
int mid = l + r >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(o);
}
//找当前线段树里存在的第k个数
// 同时 删除这个数
int query(int o, int L, int R, int k) {
if (t[o].l == t[o].r) {
t[o].sum = 0;
return t[o].l;
}
int res;
if (t[ls].sum >= k) res = query(ls, L, R, k);
else res = query(rs, L, R, k - t[ls].sum);
pushup(o);
return res;
}
} ST;
int vis[N];
vector<int> v;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++) {
a[i] = i;
}
while (m--) {
cin >> k >> x;
for (int i = 1; i <= n; i++) {
vis[i] = 0;
}
ST.build(1, 1, n);
for (int i = 1, pos = k; i <= n; i++) {
p[i] = ST.query(1, 1, n, pos);
// 下一位数是剩下的数字里面的第pos位
if (i < n) pos = ((pos - 1 + k - 1) % (ST.t[1].sum)) + 1;
}
// 根据置换p 求出环内的顺序
for (int i = 1; i <= n; i++) {
nxt[p[i]] = i;
}
for (int i = 1, now; i <= n; i++) {
if (!vis[i]) {
v.clear();
now = i;
while (!vis[now]) {
vis[now] = 1;
v.push_back(now);
now = nxt[now];
}
// 置换群快速幂
for (int j = 0, sz = v.size(); j < sz; j++) {
p[v[j]] = v[(j + x) % sz];//新的位置关系
}
}
}
for (int i = 1; i <= n; i++) {
nxt[p[i]] = a[i];
}
for (int i = 1; i <= n; i++) {
a[i] = nxt[i];
}
}
for (int i = 1; i <= n; i++) {
cout << a[i] << (i == n ? "\n" : " ");
}
return 0;
}
K. K-Bag
https://ac.nowcoder.com/acm/contest/5671/K
参考博客 2020牛客多校第六场K.K-Bag (思维?)
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
int a[N], b[N], vis[N], vis_pos[N];
int mp[N];
int n, k;
namespace Discretization { // 离散化板子
vector<int> backUp;
void discrete() {
sort(backUp.begin(), backUp.end());
backUp.erase(unique(backUp.begin(), backUp.end()), backUp.end());
}
int id(int x) {
return lower_bound(backUp.begin(), backUp.end(), x) - backUp.begin() + 1;
}
}
using namespace Discretization;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
cin >> n >> k;
int flag = 1;//判断标志
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] > k) {
flag = 0;
}
backUp.push_back(a[i]);//离散化
}
if (!flag) {
cout << "NO" << endl;
backUp.clear();
continue;
}
discrete();//离散化
for (int i = 1; i <= n; i++) {
a[i] = id(a[i]);// 离散化后的下标
}
if (n > k) {
flag = 0;
// 先判断 a[r-k+1...r]里 数值为a[r] 的个数是否多次出现
for (int r = 1, l = 1; r <= n; r++) {
vis[a[r]]++;
if (vis[a[r]] > 1) {
b[r] = 0;// b[r]表示 以r为结尾 区间长度为k的 一个区间划分 是否合法 0非法 1合法
} else {
b[r] = 1;
}
if (r >= k) {
vis[a[l++]]--;
}
}
// 但是 还有 a[r-k+1...r]里 重复数字不是在a[r]上出现的 非法划分
// 比如 k=6时 [x 3 2 3 x x] 显然 [x x x 3 2 3] [ x 3 2 3 x x] [ 3 2 3 x x x] 都是不合法的
// 但是 前面统计的时候 只有第2个3的位置 即[x x x 3 2 3] 被设置为了非法 其后面的位置都被当成了合法
// 所以 需要将 这些包含 重复数字的区间划分 设置为非法
int cnt = 0;// cnt表示 还有cnt个位置需要设置为非法
for (int i = 1; i <= n; i++) {
if (mp[a[i]]) {
cnt = max(cnt, k - (i - mp[a[i]]));
// 同时包含位置i 和上一次出现的位置 mp[a[i]] 的长度为k的区间 都是非法的
}
if (cnt) {
b[i] = 0;
cnt--;
}
mp[a[i]] = i;
}
// 特殊情况
// 补齐最后非法的区间 即 最后一段区间是非法 但是只出现了非法区间的一部分
// 不过 这一部分b[i]本来就是0 就不写了
for (int i = 1, lim = n + cnt; i <= lim; i++) {
if (b[i] == 0) {
vis_pos[(i % k) + 1] = 1;
// 那么从当前位置开始k个为一组往前分组 一直分到到第一个含有k个元素的组
// 都是不合法的分法 将第一个位置的下标 标记为1 - 不合法
}
}
for (int i = 1; i <= k; i++) {
if (vis_pos[i] == 0) {
//存在合法的起始位置
flag = 1;
break;
}
}
} else {
// 当n<=k 要么只有一组 要么是两组(即各取一部分拼接形成)
// 找到第一个重复的位置
int pos = 0;
for (int i = 1; i <= n; i++) {
vis[a[i]]++;
if (vis[a[i]] > 1) {
pos = i;
break;
}
}
// 都没有重复 显然合法
if (pos == 0) {
} else {
// 以pos为分界线划分前后两部分
// 将前面合法的统计过的部分清空
for (int i = 1; i <= pos; i++) {
vis[a[i]]--;
}
// 判断后面的是否合法
for (int i = pos; i <= n; i++) {
vis[a[i]]++;
if (vis[a[i]] > 1) {
flag = 0;
break;
}
}
}
}
if (flag) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
// init
memset(b, 0, sizeof b);
memset(vis, 0, sizeof vis);
memset(vis_pos, 0, sizeof vis_pos);
memset(mp, 0, sizeof mp);
backUp.clear();
}
return 0;
}