2022杭电多校第二场部分题解
Copy
题意:
n个数字由两种操作,操作1,把l到r复制一遍然后粘贴到r后面,操作2,求第x个数字
思路:
对于一次操作完成之后的查询,如果x小于等于r,则不会产生影响,如果大于r,那么相当于查询x-(r-l+1)的数字;
所以选择倒着预处理,对于一次操作之后所有的查询x,将他们的x全部-=(r-l+1),因为是求最终结果的异或值,所以每个
数字的贡献要么是0要么是1,可以使用bitset优化这个操作
代码:
#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'
#define SZ(v) (int) v.size()
const int N = 100010;
bitset<N> f;
int a[N];
struct T {
int op, l, r;
} q[N];
void solve(int Case) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= m; i++) {
cin >> q[i].op >> q[i].l;
if (q[i].op == 1) cin >> q[i].r;
}
f.reset();
for (int i = m; i >= 1; i--) {
int op = q[i].op;
if (op == 1) {
int l = q[i].l, r = q[i].r;
auto left = f & (~bitset<N>(0) >> (N - r - 1)); //左半部分1~r
auto right = f & (~bitset<N>(0) << (r + 1)); //取出右半部分
f = left ^ (right >> (r - l + 1)); //把右边左移(r-l+1)
} else {
int x = q[i].l;
f[x] =!f[x];
}
}
int res = 0;
for (int i = 1; i <= n; i++) {
if (f[i]) res ^= a[i];
}
cout << res << nline;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
for (cin >> _, Case = 1; Case <= _; Case++)
solve(Case);
return 0;
}
Luxury cruise ship
题意:
有三个数字7,31,365,给出一个n求最少多少个数字可以恰好凑齐n
思路:
预处理这三个数字的乘积79205以内的完全背包,打表发现180开始每个数字都可以表示出来,那么大于79205的先使用k个79205,剩下的模数79205做差即可
代码:
#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'
#define SZ(v) (int) v.size()
const int N = 80000;
int f[N * 3];
int a[4] = {0, 7, 31, 365};
int lcm(int a, int b) {
return a / __gcd(a, b) * b;
}
int m;
int d;
vector<int> v;
void init() {
memset(f, 0x3f, sizeof f);
f[0] = 0;
for (int i = 1; i <= 3; i++) {
for (int j = a[i]; j <= d; j++) {
f[j] = min(f[j], f[j - a[i]] + 1);
}
}
v.push_back(0);
for (int i = m + 1; i <= d-1 ; i++) v.push_back(f[i] - f[i - 1]);
}
void solve(int Case) {
int n;
cin >> n;
if (n < 2 * m) {
int res = f[n];
if (res >= 0x3f3f3f3f3f3f3f3f) res = -1;
cout << res << nline;
return;
}
int k = n / m;
int res = k * f[m];
k = n % m;
int sum = 0;
for (int i = 0; i <= k; i++) sum += v[i];
cout << res + sum << nline;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
m = lcm(7, lcm(31, 365));
d = m * 2;
init();
for (cin >> _, Case = 1; Case <= _; Case++)
solve(Case);
return 0;
}
ShuanQ
题意:
给出三个数字p和q和e,q是p的逆元,m(mod)没有给出,求q*e%m
思路:
先求m,然后套公式;
p*q%m=1,则pq-1=km
而且m是唯一的,因为m大于p和q,如果有两个这样的m,则乘积会大于pq,
代码:
#include <bits/stdc++.h>
#define int long long
int _ = 0, Case = 1;
using namespace std;
#define all(v) begin(v),end(v)
#define nline '\n'
#define SZ(v) (int) v.size()
int qmi(int a, int b, int p) {
int res = 1 % p;
while (b) {
if (b & 1) res = ((res % p) * (a % p)) % p;
a = ( (a % p) * (a % p) % p);
b >>= 1;
}
return res % p;
}
void solve(int Case) {
int p, q, e;
cin >> p >> q >> e;
int m = p * q - 1;
int mmax = max(p, q);
int ans = -1, cnt = 0;
if (m) {
for (int i = 2; i <= m / i; i++) {
if (m % i == 0) {
if (i > mmax) {
ans = e * q % i;
cout << ans << nline;
return;
}
}
while (m % i == 0) m /= i;
}
}
if (m > 1 and m > mmax) {
// if (qmi(p, m - 2, m) == q) {最坏情况下,mod是2e12,相乘会爆LL
ans = e * q % m;
cout << ans << nline;
return;
//}
}
cout << "shuanQ" << nline;
}
signed main() {
ios::sync_with_stdio(false); cin.tie(nullptr);
for (cin >> _, Case = 1; Case <= _; Case++)
solve(Case);
return 0;
}