GJOI 2024.7.15 总结
T1 CF1607E
简单题,直接模拟即可。
T2 CF1614C
Solution:
容易发现一种可行的构造方案就是对于每个
考虑到位运算位之间互不影响的性质,接着我们从分别考虑每一位对答案的贡献。统计的时候分类讨论一下就可以了。
qwq
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 2e5 + 10, mod = 1e9 + 7; int n, m, a[N], two[50]; namespace Segtree{ #define ls (o << 1) #define rs (o << 1 | 1) #define mid (l + r >> 1) int tag[N << 2]; void build(int o, int l, int r){ tag[o] = (1ll << 31) - 1; if(l == r) return; build(ls, l, mid); build(rs, mid + 1, r); } void pushdown(int o){ if(tag[o] != (1ll << 31) - 1){ tag[ls] &= tag[o]; tag[rs] &= tag[o]; tag[o] = (1ll << 31) - 1; } } void addtag(int o, int l, int r, int s, int t, int val){ if(s <= l && r <= t){tag[o] &= val; return;} pushdown(o); if(s <= mid) addtag(ls, l, mid, s, t, val); if(mid < t) addtag(rs, mid + 1, r, s, t, val); } void getval(int o, int l, int r){ if(l == r){a[l] = tag[o]; return;} pushdown(o); getval(ls, l, mid); getval(rs, mid + 1, r); } } using namespace Segtree; int calc(int bitid){ int cnt[2] = {1, 0}; for(int i = 1; i <= n; i++){ bool f = (a[i] & (1 << bitid)); int c[2]; c[0] = (cnt[0] + cnt[f]) % mod; c[1] = (cnt[1] + cnt[f ^ 1]) % mod; cnt[0] = c[0]; cnt[1] = c[1]; } return cnt[1]; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int T; cin >> T; two[0] = 1; for(int i = 1; i <= 40; i++) two[i] = (two[i - 1] * 2) % mod; while(T--){ cin >> n >> m; build(1, 1, n); for(int i = 1; i <= m; i++){ int l, r, v; cin >> l >> r >> v; addtag(1, 1, n, l, r, v); } getval(1, 1, n); int ans = 0; // for(int i = 1; i <= n; i++) cout << a[i] << " "; // cout << calc(0) << "\n"; for(int bit = 0; bit <= 30; bit++) ans = (ans + calc(bit) * two[bit] % mod) % mod; cout << ans << "\n"; } return 0; }
T3 CF1611G
Solution:
好题。
首先观察性质,容易发现棋盘上有两类点,他们按对角线为分类,两类点互不可达。换句话说,如果我们对棋盘进行黑白交替染色,可以得到黑白两类点,而且他们互不影响,于是可以分开讨论,下面默认只考虑一个颜色的点对。
其次我们进一步的观察,考虑怎么样的两个点可以被一次吃掉,即怎么样的
显然红点是可以到蓝点的,但是这样我们并不好去判断。于是我们再次考虑转化问题:,如果拿两条对角线去夹这个蓝点,可以发现蓝点在红点的夹角区域则等价于蓝点两条对角线都在红点两条对角线的下方。点
于是我们一个贪心即可解决问题了。
qwq
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1e6 + 10, INF = 1e18; struct point{ int x, y; }p[N], _p[N]; int n, m, tot, _t; set<int> s; bool cmp(struct point p1, struct point p2){return (p1.x != p2.x ? p1.x < p2.x : p1.y < p2.y);} int calc(){ sort(p + 1, p + tot + 1, cmp); int ans = 0; s.clear(); if(tot){ ans = 1; s.insert(p[1].y); for(int i = 2; i <= tot; i++){ if(*s.begin() > p[i].y) s.insert(p[i].y), ans++; else{ auto it = s.upper_bound(p[i].y); it--; s.erase(*it); s.insert(p[i].y); } } } return ans; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int T; cin >> T; while(T--){ cin >> n >> m; tot = _t = 0; for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ char c; cin >> c; if(c - '0'){ if((i + j) & 1) p[++tot] = {i + j, i - j}; else _p[++_t] = {i + j, i - j}; } } } int ans = calc(); for(int i = 1; i <= _t; i++) p[i] = _p[i]; tot = _t; cout << ans + calc() << "\n"; } return 0; }
T4 序列:
Statement:
给定
Solution:
套路题。
首先我们找到
对于一类中的数,我们再按
-
对于选
个数的情况:显然方案数为 。 -
对于选
个数的情况:显然方案数为数字个数。 -
对于选
个数的情况:
首先肯定是选一个
考虑将为
-
该位为 ,则我们向 节点 所对应的反方向的子树递归计算。 -
该位为 , 所对应的反方向的子树中所有数均是合法的,加入答案,并向 所对应的方向的子树递归计算。
qwq
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 1e5 + 10, M = 2, mod = 998244353; namespace Trie{ int ch[N * 60][M], siz[N * 60], cnt = 1; void init(){ for(int i = 1; i <= cnt; i++){ siz[i] = 0; ch[i][0] = ch[i][1] = 0; } cnt = 1; } void insert(int x, int bit){ int o = 1; siz[o]++; for(int i = bit; i >= 0; i--){ bool f = (x & (1ll << i)); if(!ch[o][f]) ch[o][f] = ++cnt; o = ch[o][f]; siz[o]++; } } int getans(int x, int bit, int upd){ int o = 1, ret = 0; for(int i = bit; i >= 0; i--){ if(o == 0) break; bool f = (x & (1ll << i)), pot = (upd & (1ll << i)); if(pot == 0){ ret = (ret + siz[ch[o][f ^ 1ll]]) % mod; // cout << o << " " << bit << " " << f << "\n"; o = ch[o][f]; } else o = ch[o][f ^ 1ll]; } // cout << x << " " << o << " " << siz[o] << "\n"; if(o) ret = (ret + siz[o]) % mod; return ret; } } using namespace Trie; int n, upd, a[N], b[N], bst, tot; struct zsw{ int fir, nxt; }num[N]; bool cmp(struct zsw z1, struct zsw z2){return z1.fir < z2.fir;} int calc(){ int ret = tot + 1; for(int i = 1; i <= tot; i++) if(!(b[i] & (1ll << bst))) insert(b[i], bst); for(int i = 1; i <= tot; i++) if(b[i] & (1ll << bst)) ret = (ret + getans(b[i], bst, upd)) % mod; return ret; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> upd; int t = 0, tmp = upd; for(int i = 1; i <= n; i++) cin >> a[i]; while(tmp){ if(tmp & 1ll) bst = t; tmp >>= 1; t++; } // cout << bst << "\n"; for(int i = 1; i <= n; i++) num[i].fir = (a[i] >> (bst + 1)), num[i].nxt = (num[i].fir << (bst + 1)) ^ a[i]; sort(num + 1, num + n + 1, cmp); b[++tot] = num[1].nxt; int ans = 1; num[n + 1].fir = -1; int d = 0; for(int i = 2; i <= n + 1; i++){ if(num[i].fir != num[i - 1].fir){ ans = (ans * calc()) % mod; tot = 0; init(); d++; } b[++tot] = num[i].nxt; } cout << (ans - 1 + mod) % mod; return 0; }
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18302679
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步