训练网址
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll mod_pow(ll x, ll n) {
ll res = 1;
while (n) {
if (n & 1) res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
const int maxn = 210;
bitset<maxn> X[maxn], Y[maxn], tmp[maxn];
int N;
int gauss(bitset<maxn> A[]) {
int r, c;
for (r = c = 1; c <= N; c++) {
int t = r;
for (int i = r; i <= N; i++) {
if (A[i][c]) {
t = i;
break;
}
}
if (A[t][c] == 0) {
continue;
}
swap(A[t], A[r]);
for (int i = r + 1; i <= N; i++) {
if (A[i][c]) {
A[i] ^= A[r];
}
}
r++;
//printf("### %d\n", r);
}
return N - (r - 1);
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
int x;
scanf("%d", &x);
if (x) X[i][j] = 1;
}
}
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
int x;
scanf("%d", &x);
if (x) Y[i][j] = 1;
}
}
ll cnt = 0;
for (int c = 1; c <= N; c++) {
for (int r = 1; r <= N; r++) {
tmp[r] = X[r];
tmp[r][r] = tmp[r][r] ^ Y[r][c];
}
cnt += gauss(tmp);
//printf("*** %lld\n", cnt);
}
printf("%lld\n", mod_pow(2, cnt));
return 0;
}
#include
#include
#include
using namespace std;
typedef long long ll;
int main() {
ll x, y, z;
cin >> x >> y >> z;
ll ans;
if (x > y) {
ll m = x - y;
if (m % 3 == 0 || m % 3 == 1) {
ans = 2 * (y + m / 3) + m / 3;
}
else{
ans = 2 * (y + m / 3) + m / 3 + 1;
}
}
else {
ll m = y - x;
if (m % 3 == 0 || m % 3 == 1) {
ans = 2 * (x + m / 3) + 4 * (m / 3);
}
else{
ans = 2 * (x + m / 3) + 4 + 4 * (m / 3);
}
}
printf("%lld\n", ans);
return 0;
}
#include
#include
#include
#define x first
#define y second
using namespace std;
const int maxn = 100010;
typedef long long ll;
typedef pair<ll, ll> P;
P w[maxn];
int N;
bool cmp(const P& a, const P& b) {
return a.y < b.y || a.y == b.y && a.x > b.x;
}
int main() {
scanf("%d", &N);
for (int i = 1; i <= N; i++) {
scanf("%lld%lld", &w[i].x, &w[i].y);
}
sort(w + 1, w + N + 1, cmp);
ll st = w[1].x, ed = w[1].y;
ll ans = 0;
for (int i = 1; i <= N; i++) {
ans += max(st, w[i].x);
st = max(st, w[i].x);
}
cout << ans << endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long ll;
ll X, Y;
vector<int> ten_two(ll x) {
vector<int> v;
while (x) {
v.push_back(x % 2);
x >>= 1;
}
return v;
}
ll two_ten(vector<int> v) {
ll res = 0;
for (int i = 0; i < v.size(); i++) {
res += (ll)v[i] * (1LL << i);
}
return res;
}
int main() {
cin >> X >> Y;
if ((X ^ Y) < X) {
printf("1\n%lld\n", X ^ Y);
return 0;
}
printf("2\n");
vector<int> xx = ten_two(X), yy = ten_two(Y);
int szx = xx.size(), szy = yy.size();
vector<int> ans1;
for (int i = 0; i < szy; i++) ans1.push_back(xx[i] ^ yy[i]);
printf("%lld ", two_ten(ans1));
vector<int> ans2;
ll res = 0;
for (int i = szy; i < szx; i++) {
res += (ll)xx[i] * (1LL << i);
}
printf("%lld\n", res);
return 0;
}
问题分成两种情况,有边和无边,混在一起考虑比较困难,想到分开来考虑,可以想到二分图的模型。树本身就是一个二分图(没有奇环)。
将树上的点黑白染色后分成两个部分。先来考虑两个部分内部的情况,可以将白点的最末两位赋上01,将黑点的最末两位赋上10,这样白点内部和黑点内部就能满足限制了,且白点和黑点的最后两位或起来为11,而边只能是一端白点,一端黑点,所以也满足限制。再来考虑黑白之间的情况,可以从黑部和白部中点数较少的那个部分着手,不妨设黑部点数较少,我们将第一个黑点的高58位赋上111…1110,第二个赋上111…1101,第三个赋上111…1011,依此类推,因为黑部点数较少,所以少于等于50个,所以58位足以标识所有的点。然后对于每个白点,它连了几个黑点,就把那几个黑点高58位中为0的位置赋上1,其余位置赋上0,即可满足限制。
————————————————
原文链接:https://blog.csdn.net/weixin_43466755/article/details/112383754
int flag = (cnt_odd < cnt_even);
,然后 if ((d[i] & 1) == flag)
就可以判断在奇数多的情况下操作还是在偶数多的情况下操作。ans[u] |= (~ans[v])
,因为非运算会把整个64位都反过来,相当于反码。应该ans[u] |= (B ^ ans[v])
,这样子就把0给抠出来了。#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 110, maxm = 210;
int h[maxn], e[maxm], ne[maxm], idx;
int d[maxn], N, CNT[maxn];
ll ans[maxn];
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u, int fa) {
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
if (v == fa) continue;
d[v] = d[u] + 1;
dfs(v, u);
}
}
int main() {
memset(h, -1, sizeof h);
scanf("%d", &N);
for (int i = 1; i < N; i++) {
int a, b;
scanf("%d%d", &a, &b);
add(a, b), add(b, a);
}
dfs(1, -1);
int cnt_odd = 0, cnt_even = 0;
for (int i = 1; i <= N; i++) {
if (d[i] & 1) {
cnt_odd++;
}
else {
cnt_even++;
}
}
int flag = (cnt_odd < cnt_even);
int cnt = 0;
ll B = (1LL << 58) - 1;
for (int i = 1; i <= N; i++) {
//可以用这个方式判断 cnt_odd 多还是 cnt_even 多。
if ((d[i] & 1) == flag) {
ans[i] |= B;
ans[i] ^= (1LL << cnt);
cnt++;
}
}
for (int u = 1; u <= N; u++) {
if ((d[u] & 1) != flag) {
for (int i = h[u]; i != -1; i = ne[i]) {
int v = e[i];
ans[u] |= (B ^ ans[v]);
//printf("%lld\n", ans[u]);
}
}
}
for (int i = 1; i <= N; i++) {
ans[i] <<= 2;
if (d[i] & 1) ans[i] |= 1;
else ans[i] |= 2;
}
for (int i = 1; i <= N; i++) {
printf("%lld%c", ans[i], i == N ? '\n' : ' ');
}
return 0;
}
#include
#include
#include
#include
using namespace std;
const int maxn = 100010, maxm = 30 * maxn;
int w[maxn], sz[maxm], son[maxm][2], idx;
int N, M;
const int lg = 29, INF = (1 << 30);
vector<vector<int>> kth;
void insert(int x) {
int p = 0;
for (int i = lg; i >= 0; i--) {
sz[p]++;
int u = ((x >> i) & 1);
if (!son[p][u]) son[p][u] = ++idx;
p = son[p][u];
}
sz[p]++;
}
void dfs(int u, int d) {
int l = son[u][0], r = son[u][1];
if (!l && !r) {
kth[u][1] = 0;
return;
}
if (l) dfs(l, d - 1);
if (r) dfs(r, d - 1);
for (int i = 1; i <= sz[u]; i++) {
kth[u][i] = INF;
//如果当前的 S 的第 d 位是 0。
if (sz[l] >= i) kth[u][i] = min(kth[u][i], kth[l][i]);
//那么答案就在右子树里面
else kth[u][i] = min(kth[u][i], (1 << d) ^ kth[r][i - sz[l]]);
//如果当前的 S 的第 d 位是 1.
if (sz[r] >= i) kth[u][i] = min(kth[u][i], kth[r][i]);
else kth[u][i] = min(kth[u][i], (1 << d) ^ kth[l][i - sz[r]]);
}
}
void build() {
//用resize,防止爆空间。
for (int i = 1; i <= N; i++) {
insert(w[i]);
}
kth.resize(idx + 1);
for (int i = 0; i <= idx; i++) {
kth[i].resize(sz[i] + 1);
}
for (int i = 0; i <= N; i++) {
kth[0][i] = INF;
}
dfs(0, lg);
}
int walk(int& p, int& k, int t) {
if (son[p][t] && sz[son[p][t]] >= k) {
p = son[p][t];
return 0;
}
else {
if (son[p][t]) k -= sz[son[p][t]];
p = son[p][1 ^ t];
return 1;
}
}
int query(int x, int lim, int k, int flag) {
int p = 0, S = 0, res = INF;
for(int i = lg; i >= 0; i--){
int t = ((x >> i) & 1);
//L的第lim的位置一定是0,R第lim的位置一定是1.
//我们让第lim的位置仍然贴合下界(上界)
//因此,从第 lim - 1 的位置,就可以0和1随便填了。
if(i < lim && t == flag){
//t==flag,比如L这一位是0的时候,那么S的这一位可以填1也可以填0
//当L这一位是1的时候,S的这一位只能填1. 因为要贴合下界。对于R也是同理
int tp = p, ts = S, tk = k;
//这一步表示不贴和下界的情况,由于后面的数可以随意填,res 就是当前的S,后面拼上 t^1,然后再拼上 kth[p的儿子][k].
if(walk(tp, tk, t ^ 1)) ts ^= (1 << i);
res = min(res, ts ^ kth[tp][tk]);
}
//这一步表示贴合下界(上界)的情况。
if(walk(p, k, t)) S ^= (1 << i);
}
//S贴合下界的情况要在最后一步更写一下答案。
res = min(res, S ^ kth[p][k]);
return res;
}
int main() {
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; i++) scanf("%d", &w[i]);
build();
while (M--) {
int L, R, K;
scanf("%d%d%d", &L, &R, &K);
int p = lg;
while (p >= 0 && ((L >> p) & 1) == ((R >> p) & 1)) p--;
printf("%d\n", min(query(L, p, K, 0), query(R, p, K, 1)));
}
return 0;
}
#include
#include
#include
#include
using namespace std;
typedef long long ll;
ll dp[64][2][2][2];
const int maxn = 110;
bitset<maxn> w, L_b;
int M;
ll L;
int is_even(int x) {
int res = 0;
while (x) {
res ^= (x & 1);
x >>= 1;
}
return res;
}
ll calc(int lim, int s, int t) {
int end = lim ? L % 128 : 127;
//printf("*** %d\n", end);
int res = 0;
for (int i = 0; i <= end; i++) {
int f = 1;
for (int j = 0; j < M; j++) {
if (i + j < 128) f &= ((is_even(i + j) ^ s) == w[j]);
else f &= ((is_even(i + j) ^ s ^ t) == w[j]);
}
res += f;
}
return res;
}
ll dfs(int pos, int lim, int s, int t) {
//s表示第8位及之前的数字的1的个数,t表示从第8位开始往前数连续的1的个数。
if (dp[pos][lim][s][t] != -1) return dp[pos][lim][s][t];
if (pos <= 6) {
return dp[pos][lim][s][t] = calc(lim, s, t);
}
int up = lim ? L_b[pos] : 1;
ll res = 0;
for (int i = 0; i <= up; i++) {
//i & (!t) 很有趣。t = 0 表示最后连续的1是偶数。
//如果当前位填 0 的话,那么连续被打断,最后连续的1的个数显然是偶数(连续个数为0).
//如果当前填1的话,那么就把之前的状态 t 反转一下即可。
res += dfs(pos - 1, i == up && lim, s ^ i, i & (!t));
}
//注意贴合上界的情况下可能被复用。
if (lim == 0) dp[pos][lim][s][t] = res;
return res;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
w.reset();
memset(dp, -1, sizeof dp);
scanf("%d%lld", &M, &L);
for (int i = 0; i < M; i++) {
int x;
scanf("%d", &x);
w[i] = x;
}
int len = 0;
//L后面还要用,别在这里清零了
ll _L = L;
while (_L) {
L_b[len++] = (_L & 1);
_L >>= 1;
}
printf("%lld\n", dfs(len - 1, 1, 0, 0));
}
return 0;
}
#include
#include
#include
using namespace std;
int main() {
int N, K;
scanf("%d%d", &N, &K);
if (N < K) printf("2\n");
else printf("%d\n", (2 * N + K - 1) / K);
return 0;
}