A
左右移动、上下移动可以抵消
注意特判不能移动但必须移动的情况
int main() {
int t; cin >> t;
while (t--) {
int a, b, c, d; cin >> a >> b >> c >> d;
int x, y, x1, y1, x2, y2; cin >> x >> y >> x1 >> y1 >> x2 >> y2;
b -= a; d -= c;
if (x1 <= x + b && x + b <= x2 && y1 <= y + d && y + d <= y2) {
if ((b == 0 && a != 0 && x1 == x2) || (d == 0 && c != 0 && y1 == y2)) {
cout << "No" << endl;
}
else {
cout << "Yes" << endl;
}
}
else {
cout << "No" << endl;
}
}
}
B
因数分解
遍历因子,将相同因子的数标记到一个块内,用过的数不能再用
const int maxn = 1e3;
int vis[maxn];
vector<int> pr[maxn];
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int t; cin >> t;
while (t--) {
int n; cin >> n;
for (int i = 0; i < n; ++i) {
vis[i] = 0;
int x; cin >> x;
for (int j = 2; j * j <= x; ++j) {
if (x % j == 0) {
pr[j].push_back(i);
if (j * j != x) {
pr[x / j].push_back(i);
}
}
}
}
int tot = 1;
for (int i = 2; i < maxn; ++i) {
bool flg = false;
for (int j = 0; j < pr[i].size(); ++j) {
if (vis[pr[i][j]]) continue;
vis[pr[i][j]] = tot;
flg = true;
}
if (flg) tot++;
pr[i].clear();
}
cout << tot - 1 << '\n';
for (int i = 0; i < n; ++i) {
if (i == n - 1) cout << vis[i] << '\n';
else cout << vis[i] << ' ';
}
}
}
C
将隔k个位置用并查集维护,再维护一下回文串的位置
遍历并查集,每个团中保留出现次数最多的字符
const int maxn = 2e5 + 5;
char str[maxn];
int f[maxn];
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
int cnt[maxn][30];
int main() {
int t; scanf("%d", &t);
while (t--) {
int n, k; scanf("%d%d", &n, &k);
scanf("%s", str);
for (int i = 0; i < n; ++i) {
f[i] = i;
for (int j = 0; j < 26; ++j) {
cnt[i][j] = 0;
}
cnt[i][str[i] - 'a']++;
}
for (int i = k; i < n; i += k) {
for (int j = 0; j < k; ++j) {
int a = find(j), b = find(i + j);
if (a == b) continue;
f[b] = a;
for (int j = 0; j < 26; ++j) {
cnt[a][j] += cnt[b][j];
}
}
}
for (int i = 0; i < n; ++i) {
int a = find(i), b = find(n - 1 - i);
if (a == b) continue;
f[b] = a;
for (int j = 0; j < 26; ++j) {
cnt[a][j] += cnt[b][j];
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
if (i == f[i]) {
int tar = -1, sum = 0;
for (int j = 0; j < 26; ++j) {
sum += cnt[i][j];
if (tar == -1 || cnt[i][j] > cnt[i][tar]) {
tar = j;
}
}
ans += sum - cnt[i][tar];
}
}
printf("%d\n", ans);
}
}
D
尝试找到一种通用解法
按照题意,要出现贪心选择当时大的元素而舍弃小的元素,以至于结果偏小
对k的二进制s,我们使贪心的结果为0,正确答案为k。
设k=5,s=101做例子,则有:
start | a | a |
---|---|---|
b | a | 101 |
其中a路线为贪心,b路线为正确答案
要使贪心结果为0,根据&的特性,构建a=1000,则1000%101=0,b=101,则1000&101=0,101&101=101
1101 | 1000 | 1000 |
---|---|---|
101 | ? | 101 |
要使最右下方的a[i][j]&dp[i-1][j]=a[i][j]&dp[i][j-1],因此?=1101,此处贪心会得到1000,最终结果即为0,与答案相差k
int main() {
int k; scanf("%d", &k);
int pos = 0;
for (int i = 0; i < 20; ++i) {
if ((k >> i) & 1) {
pos = i;
}
}
int incre = k + (1 << (pos + 1)), incre_no_k = 1 << (pos + 1);
printf("%d %d\n", 2, 3);
printf("%d %d %d\n%d %d %d\n", incre, incre_no_k, incre_no_k, k, incre, k);
}
E
分析给出条件有单个格子+2和相邻的格子+1,使最终格子高度相同。
单个格子+2不会改变该格子高度的奇偶性(操作1),相邻格子+1会改变高度的奇偶性(操作2),且相同奇偶性一定可以达到相同高度
分析nm为奇数的情况:若高度为奇数和偶数的格子个数为偶数时,一定可以通过操作2变成另一种,因此该情况一定满足可以达到想要高度,答案即为 ( R − L + 1 ) n ∗ m (R-L+1)^{n*m} (R−L+1)n∗m
nm为偶数:只有高度为奇数和偶数的格子个数都要为偶数才能达到相同高度,a表示可选的偶数高度,b表示可选的奇数高度,答案 ∑ 0 ≤ i ≤ n , i % 2 = = 0 ( n ∗ m i ) a i b n ∗ m − i = ( a + b ) n ∗ m − ( a − b ) n ∗ m \sum\limits_{0\le i\le n,i\%2==0}{{n*m}\choose{i}}a^ib^{n*m-i}=(a+b)^{n*m}-(a-b)^{n*m} 0≤i≤n,i%2==0∑(in∗m)aibn∗m−i=(a+b)n∗m−(a−b)n∗m
typedef long long ll;
const int mod = 998244353;
ll qpow(ll a, ll b) {
ll res = 1;
while (b) {
if (b & 1) res = res * a % mod;
b >>= 1;
a = a * a % mod;
}
return res;
}
int main() {
ll n, m, L, R; scanf("%lld%lld%lld%lld", &n, &m, &L, &R);
n *= m;
if (n & 1) {
printf("%lld\n", qpow(R - L + 1, n));
}
else {
ll ans = qpow(R - L + 1, n) + ((R - L + 1) & 1 ? 1 : 0);
ans = ans * qpow(2, mod - 2) % mod;
printf("%lld\n", ans);
}
}