Codeforces Round #630 (Div. 2)

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做例子,则有:

startaa
ba101

其中a路线为贪心,b路线为正确答案
要使贪心结果为0,根据&的特性,构建a=1000,则1000%101=0,b=101,则1000&101=0,101&101=101

110110001000
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} (RL+1)nm
n
m为偶数:只有高度为奇数和偶数的格子个数都要为偶数才能达到相同高度,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} 0in,i%2==0(inm)aibnmi=(a+b)nm(ab)nm

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);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值