给定一个长度为 n ( 1 ≤ n ≤ 1 e 4 ) n\ \ (1\leq n\leq 1\mathrm{e}4) n (1≤n≤1e4)的、元素范围为 [ − 1 e 5 , 1 e 5 ] [-1\mathrm{e}5,1\mathrm{e}5] [−1e5,1e5]的序列 a [ ] a[] a[],输出 a [ ] a[] a[]的值域乘 n n n的值.
void solve() {
int n; cin >> n;
valarray a(n);
for (int i = 0; i < n; i++) cin >> a[i];
cout << (ll)n * (a.max() - a.min());
}
int main() {
solve();
}
给定一个长度为 n ( 1 ≤ n ≤ 1 e 4 ) n\ \ (1\leq n\leq 1\mathrm{e}4) n (1≤n≤1e4)的、元素范围为 [ 1 , 1 e 9 ] [1,1\mathrm{e}9] [1,1e9]的整数序列 a [ ] a[] a[],若其中奇数的个数与偶数的个数相差不超过 1 1 1,输出"Good";否则输出"Not Good".
void solve() {
int n; cin >> n;
int odd = 0, even = 0;
while (n--) {
int a; cin >> a;
if (a & 1) odd++;
else even++;
}
cout << (abs(odd - even) <= 1 ? "Good" : "Not Good");
}
int main() {
solve();
}
给定整数 a , b ( 1 ≤ a ≤ b ≤ 1000 ) a,b\ \ (1\leq a\leq b\leq 1000) a,b (1≤a≤b≤1000),求 a b \dfrac{a}{b} ba,四舍五入保留小数点后 k ( 1 ≤ k ≤ 1000 ) k\ \ (1\leq k\leq 1000) k (1≤k≤1000)位.
显然当且仅当 a = b a=b a=b时 a b \dfrac{a}{b} ba的整数部分为 1 1 1,其余情况整数部分为 0 0 0.
注意到 a b \dfrac{a}{b} ba小数点后第 1 1 1位即 10 a b \dfrac{10a}{b} b10a的整数部分,但 k k k最大为 1000 1000 1000,乘 1000 1000 1000次会爆掉.注意到对答案有贡献的只有 a a a模 b b b的余数,故每次 a ∗ = 10 a*=10 a∗=10,计算答案后 a % = b a\%=b a%=b即可.
void solve() {
int a, b, k; cin >> a >> b >> k;
if (a == b) {
cout << "1." << string(k, '0');
return;
}
string ans = "0.";
for (int i = 0; i <= k; i++) {
a *= 10;
ans.push_back(a / b + '0');
a %= b;
}
if (ans.back() >= '5') {
ans.pop_back();
char tmp = ans.back() + 1;
ans.pop_back();
ans.push_back(tmp);
}
else ans.pop_back();
cout << ans;
}
int main() {
solve();
}
有 t ( 1 ≤ t ≤ 100 ) t\ \ (1\leq t\leq 100) t (1≤t≤100)组测试数据.每组测试数据给定一个长度为 n ( 1 ≤ n ≤ 1 e 5 ) n\ \ (1\leq n\leq 1\mathrm{e}5) n (1≤n≤1e5)的序列 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}^9) a1,⋯,an (1≤ai≤1e9).数据保证所有测试数据的 n n n之和不超过 5 e 5 5\mathrm{e}5 5e5.
对每组测试数据,若存在 i , j ∈ [ 1 , n ] , i ≠ j s . t . a i x o r a j = 1 i,j\in[1,n],i\neq j\ s.t.\ a_i\ \mathrm{xor}\ a_j=1 i,j∈[1,n],i=j s.t. ai xor aj=1,则输出"Yes";否则输出"No".
用哈希表查找是否存在元素 a i x o r 1 a_i\ \mathrm{xor}\ 1 ai xor 1即可.
void solve() {
int n; cin >> n;
umap cnt;
bool flag = false;
while (n--) {
int a; cin >> a;
if (cnt.count(a ^ 1)) flag = true;
cnt[a]++;
}
cout << (flag ? "Yes" : "No") << endl;
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
对字符串 s s s,有如下两种操作:①删除 s s s的尾字符;②在 s s s的尾部添加一个字符.对字符串 s s s,记从下标 i ( 0 ≤ i < n ) i\ \ (0\leq i
有 t t t组测试数据.每组测试数据输入一个字符串 s ( 2 ≤ ∣ s ∣ ≤ 1 e 6 ) s\ \ (2\leq |s|\leq 1\mathrm{e}6) s (2≤∣s∣≤1e6).数据保证所有测试数据的 ∣ s ∣ |s| ∣s∣之和不超过 5 e 6 5\mathrm{e}6 5e6.
对每组测试数据,输出 d ( s i , s j ) d(s_i,s_j) d(si,sj)的最大值.
设 l e n = ∣ s ∣ len=|s| len=∣s∣.
①若 s s s只有一种字符,则取整个串为 s i s_i si,取尾字符为 s j s_j sj,此时 d ( s i , s j ) = l e n − 1 d(s_i,s_j)=len-1 d(si,sj)=len−1,显然是最大值.
②若 s s s有多种字符,找到第一个与 s [ 0 ] s[0] s[0]不同的字符 s [ i ] ( 1 ≤ i < l e n ) s[i]\ \ (1\leq i
此时 d ( s i , s j ) = l e n + ( l e n − i ) = 2 l e n − i d(s_i,s_j)=len+(len-i)=2len-i d(si,sj)=len+(len−i)=2len−i,显然是最大值.
void solve() {
string s; cin >> s;
int len = s.length();
if (s == string(len, s[0])) cout << len - 1 << endl;
else {
for (int i = 1; i < len; i++) {
if (s[i] != s[0]) {
cout << 2 * len - i << endl;
return;
}
}
}
}
int main() {
CaseT // 单测时注释掉该行
solve();
}
给定整数 n , k ( 1 ≤ k , n ≤ 1 e 5 ) n,k\ \ (1\leq k,n\leq 1\mathrm{e}5) n,k (1≤k,n≤1e5),求长度为 2 n 2n 2n的、包含 k k k种括号的合法括号序列数,答案对 1 e 9 + 7 1\mathrm{e}9+7 1e9+7取模.
长度为 2 n 2n 2n的、包含 1 1 1种括号的合法括号序列数即Catalan数 H n H_n Hn.
有 k k k种括号时,只需考虑左括号,共 n n n个,每个左括号有 k k k种选择,另外 n n n个右括号只能取与其对应的左括号的相同类型,方案数为 k n k^n kn.
综上, a n s = H n ⋅ k n ans=H_n\cdot k^n ans=Hn⋅kn.
const int MAXN = 2e5 + 5;
const int MOD = 1e9 + 7;
int fac[MAXN], ifac[MAXN];
void init() { // 预处理阶乘及其逆元
fac[0] = 1;
for (int i = 1; i < MAXN; i++) fac[i] = (ll)fac[i - 1] * i % MOD;
ifac[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2, MOD);
for (int i = MAXN - 1; i; i--) ifac[i - 1] = (ll)ifac[i] * i % MOD;
}
int C(int n, int m) { // 组合数C(n,m)
return (ll)fac[n] * ifac[m] % MOD * ifac[n - m] % MOD;
}
void solve() {
init();
int n, k; cin >> n >> k;
int ans = (ll)C(2 * n, n) * qpow(n + 1, MOD - 2, MOD) % MOD * qpow(k, n, MOD) % MOD;
cout << ans;
}
int main() {
solve();
}
给定一张包含 n n n个节点、 m m m条边的无向图.某人的路径是 a 1 , ⋯ , a k a_1,\cdots,a_k a1,⋯,ak,他从节点 a 1 a_1 a1出发,严格按照路径行进.当他在节点 a i a_i ai时,他会随机地选择一条从节点 a i a_i ai到节点 a i + 1 a_{i+1} ai+1的路径并行进到节点 a i + 1 a_{i+1} ai+1.注意他可能多次经过同一节点.每条边上有一个 1 ∼ 9 1\sim 9 1∼9的整数,当他通过该边时,他会将该数字从左到右地写在纸上,到达终点后纸上是一个 ( k − 1 ) (k-1) (k−1)位数.求他到达终点后纸上的数字的期望,答案对 998244853 998244853 998244853取模.
第一行输入三个整数 n , m , k ( 2 ≤ n , m , k ≤ 3 e 5 ) n,m,k\ \ (2\leq n,m,k\leq 3\mathrm{e}5) n,m,k (2≤n,m,k≤3e5).接下来 m m m行每行输入三个整数 u , v , w ( 1 ≤ u , v ≤ n , u ≠ v , 1 ≤ w ≤ 9 ) u,v,w\ \ (1\leq u,v\leq n,u\neq v,1\leq w\leq 9) u,v,w (1≤u,v≤n,u=v,1≤w≤9),表示存在一条从节点 u u u到节点 v v v的无向边,其上的数字为 w w w.最后一行输入 k k k个整数 a 1 , ⋯ , a k ( 1 ≤ a i ≤ n , a i ≠ a i + 1 ) a_1,\cdots,a_k\ \ (1\leq a_i\leq n,a_i\neq a_{i+1}) a1,⋯,ak (1≤ai≤n,ai=ai+1).
若他无法到达终点,输出"Stupid Msacywy!";否则输出他到达终点后纸上的数字的期望,答案对 998244853 998244853 998244853取模.
类似于游走,求出路径路径数、边权和,更新答案即可.
注意模数不是 998244353 998244353 998244353.
const int MAXN = 3e5 + 5;
const int MOD = 998244853;
int n, m, k; // 节点数、边数、路径节点数
vii edges[MAXN];
int a[MAXN]; // 路径
void get(int u, int v, int& cnt, int& sum) { // 求从节点u到节点v的路径数cnt和边权和sum
cnt = sum = 0; // 注意清空
for (auto& [nxt, w] : edges[u]) {
if (nxt == v) {
cnt++;
sum += w;
}
}
}
void solve() {
cin >> n >> m >> k;
while (m--) {
int u, v, w; cin >> u >> v >> w;
edges[u].push_back({ v,w }), edges[v].push_back({ u,w });
}
for (int i = 0; i < k; i++) cin >> a[i];
ll ans = 0;
for (int i = 0; i < k - 1; i++) {
int cnt = 0, sum = 0; // 路径数、边权和
get(a[i], a[i + 1], cnt, sum);
if (!cnt) {
cout << "Stupid Msacywy!";
return;
}
ans = ((ll)ans * 10 + (ll)sum * qpow(cnt, MOD - 2, MOD) % MOD) % MOD;
}
cout << ans;
}
int main() {
solve();
}
传输 n × n n\times n n×n的 0 − 1 0-1 0−1矩阵 A A A的过程中有些元素可能丢失,丢失的元素用 − 1 -1 −1表示.原矩阵有一个行校验码、列校验码,分别是行元素的异或值、列元素的异或值,它们在传输过程中不会丢失.给定 A A A和各行的行校验码、各列的列校验码,判断是否能确定原矩阵,若能则输出原矩阵;否则输出 − 1 -1 −1.
第一行输入一个整数 n ( 1 ≤ n ≤ 1000 ) n\ \ (1\leq n\leq 1000) n (1≤n≤1000).接下来输入一个 n × n n\times n n×n的 0 − 1 0-1 0−1矩阵 A A A,元素范围 { − 1 , 0 , 1 } \{-1,0,1\} {−1,0,1}.接下来输入 n n n个整数 r 1 , ⋯ , r n r_1,\cdots,r_n r1,⋯,rn,表示各行的行校验码.接下来输入 n n n个整数 c 1 , ⋯ , c n c_1,\cdots,c_n c1,⋯,cn,表示各列的列校验码.数据保证至少存在一种 − 1 -1 −1的取法使得矩阵满足各行的行校验码和各列的列校验码.
维护每行、列 − 1 -1 −1的个数 r o w c n t [ ] rowcnt[] rowcnt[]和 c o l c n t [ ] colcnt[] colcnt[].显然能确定填 0 0 0还是 1 1 1的只有 − 1 -1 −1的个数为 1 1 1的行或列,填入后更新 r o w c n t [ ] rowcnt[] rowcnt[]和 c o l c n t [ ] colcnt[] colcnt[].用BFS完成填数过程,初始时先将只有一个 − 1 -1 −1的行和列入队.①对 − 1 -1 −1在行的情况, − 1 -1 −1所在的列号 p o s pos pos当且仅当 c o l c n t [ p o s ] colcnt[pos] colcnt[pos]减到 1 1 1时入队;②对 − 1 -1 −1在列的情况, − 1 -1 −1所在的行号 p o s pos pos当且仅当 r o w c n t [ p o s ] rowcnt[pos] rowcnt[pos]减到 1 1 1时入队.
const int MAXN = 1005;
int n;
int a[MAXN][MAXN];
int rowcnt[MAXN], colcnt[MAXN]; // 行、列-1的个数
int row[MAXN], col[MAXN]; // 行校验码、列校验码
void bfs() {
qii que; // first为-1所在的行或列,second行为1,列为2
// 只有一个-1的行和列入队
for (int i = 1; i <= n; i++)
if (rowcnt[i] == 1) que.push({ i,1 });
for (int j = 1; j <= n; j++)
if (colcnt[j] == 1) que.push({ j,2 });
while (que.size()) {
auto& [idx, op] = que.front(); que.pop();
int cnt = 0; // 行或列中1的个数
int pos = -1; // 行或列中-1的位置
if (op == 1) { // 行
for (int j = 1; j <= n; j++) {
if (~a[idx][j]) cnt += a[idx][j];
else pos = j;
}
if (!rowcnt[idx] || !colcnt[pos]) continue; // 已无-1
a[idx][pos] = row[idx] ^ (cnt & 1); // 填数
rowcnt[idx]--, colcnt[pos]--; // 更新行、列-1的个数
if (colcnt[pos] == 1) que.push({ pos,2 }); // 列-1的个数减到1时入队
}
else { // 列
for (int i = 1; i <= n; i++) {
if (~a[i][idx]) cnt += a[i][idx];
else pos = i;
}
if (!rowcnt[pos] || !colcnt[idx]) continue; // 已无-1
a[pos][idx] = col[idx] ^ (cnt & 1); // 填数
rowcnt[pos]--, colcnt[idx]--; // 更新行、列-1的个数
if (rowcnt[pos] == 1) que.push({ pos,1 }); // 行-1的个数减到1时入队
}
}
}
void solve() {
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
if (a[i][j] == -1) rowcnt[i]++, colcnt[j]++;
}
}
for (int i = 1; i <= n; i++) cin >> row[i];
for (int i = 1; i <= n; i++) cin >> col[i];
bfs();
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
if (a[i][j] == -1) {
cout << -1;
return;
}
}
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) cout << a[i][j] << " \n"[j == n];
}
int main() {
solve();
}
Linear Congruence Method(LCG)是产生伪随机数的经典方法,它基于递推公式 x n + 1 = ( a x n + b ) m o d m x_{n+1}=(ax_n+b)\ \mathrm{mod}\ m xn+1=(axn+b) mod m,其中 { x n } \{x_n\} {xn}是产生的伪随机数, a , b , m , x 0 a,b,m,x_0 a,b,m,x0是给定的常数.给定数 x x x,判断它能否由上述的LCG产生.
第一行输入五个整数 a , b , m , x 0 , x ( 0 ≤ a , b , x 0 , x < m ≤ 1 e 9 , m ∈ p r i m e s ) a,b,m,x_0,x\ \ (0\leq a,b,x_0,x
若 x x x能由上述的LCG产生,输出"YES";否则输出"NO".
本题是https://www.luogu.com.cn/problem/P3306的弱化版.
已知条件是 x 0 x_0 x0,不方便,先特判 x 0 = x x_0=x x0=x的情况,其余情况求出 x 1 x_1 x1,转化为已知 x 1 x_1 x1.
下面要判断的数 x x x用 t t t表示,模数 m m m用 p p p表示.
特判 a = 0 , 1 ; b = 0 a=0,1;b=0 a=0,1;b=0的情况,下面讨论 a ≥ 2 , b ≥ 1 a\geq 2,b\geq 1 a≥2,b≥1的情况:
先求 x n = ( a x n − 1 + b ) ( m o d p ) x_n=(ax_{n-1}+b)\ \ (\mathrm{mod}\ p) xn=(axn−1+b) (mod p)的通项,可先求出 x n = a x n − 1 + b x_n=ax_{n-1}+b xn=axn−1+b的通项,再 m o d p \mathrm{mod}\ p mod p.由不动点法知: x n + b a − 1 = a ( x n − 1 + b a − 1 ) = ⋯ = a n − 1 ( x 1 + b a − 1 ) x_n+\dfrac{b}{a-1}=a\left(x_{n-1}+\dfrac{b}{a-1}\right)=\cdots=a^{n-1}\left(x_1+\dfrac{b}{a-1}\right) xn+a−1b=a(xn−1+a−1b)=⋯=an−1(x1+a−1b).
考虑求同余方程 t + b a − 1 ≡ a n − 1 ( x 1 + b a − 1 ) ( m o d p ) t+\dfrac{b}{a-1}\equiv a^{n-1}\left(x_1+\dfrac{b}{a-1}\right)\ \ (\mathrm{mod}\ p) t+a−1b≡an−1(x1+a−1b) (mod p)的非负整数解,其中只有 n n n是变量,整理得 a n − 1 ≡ t + b a − 1 x 1 + b a − 1 ( m o d p ) a^{n-1}\equiv \dfrac{t+\dfrac{b}{a-1}}{x_1+\dfrac{b}{a-1}}\ \ (\mathrm{mod}\ p) an−1≡x1+a−1bt+a−1b (mod p).因 1 ≤ a − 1 ≤ p − 2 1\leq a-1\leq p-2 1≤a−1≤p−2,则 gcd ( a − 1 , p ) = 1 \gcd(a-1,p)=1 gcd(a−1,p)=1,可用Fermat小定理求 a − 1 a-1 a−1模 p p p的逆元.特判 x 1 + b a − 1 x_1+\dfrac{b}{a-1} x1+a−1b是 p p p的倍数的情况,此时 x n = − b a − 1 x_n=-\dfrac{b}{a-1} xn=−a−1b,其余情况RHS是整数,转化为求 a n − 1 ≡ b ′ ( m o d p ) a^{n-1}\equiv b'\ \ (\mathrm{mod}\ p) an−1≡b′ (mod p)的解,用BSGS算法.
特判:
(1) a = 0 a=0 a=0时,①若 x 1 = t x_1=t x1=t,则输出 1 1 1;②若 b = t b=t b=t,则输出 2 2 2;③其余情况无解.
(2) a = 1 a=1 a=1时,
①若 b = 0 b=0 b=0,则 x n = x n − 1 x_n=x_{n-1} xn=xn−1.若 x 1 = t x_1=t x1=t,则输出 1 1 1,其余情况无解.
②通项为 x n = x 1 + ( n − 1 ) b x_n=x_1+(n-1)b xn=x1+(n−1)b,转化为解不定方程 ( n − 1 ) b + x 1 ≡ t ( m o d p ) (n-1)b+x_1\equiv t\ \ (\mathrm{mod}\ p) (n−1)b+x1≡t (mod p),即求不定方程 ( n − 1 ) b + m p = t − x 1 (n-1)b+mp=t-x_1 (n−1)b+mp=t−x1最小正整数解,用扩展Euclid算法.
int exgcd(int a, int b, int& x, int& y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
ll bsgs(int a, int b, int p) {
if (1 % p == b % p) return 0; // 特判t=0,因p可能为1,故写1%p
int k = sqrt(p) + 1; // 分块数
// 预处理出所有b * a^y (mod p)
umap hash;
for (int i = 0, j = b % p; i < k; i++) {
hash[j] = i; // 记录值的同时记录对应的y,较大的y会覆盖较小的y
j = (ll)j * a % p;
}
// 预处理出a^k
int ak = 1;
for (int i = 0; i < k; i++) ak = (ll)ak * a % p;
// 遍历x∈[1,k],在哈希表中查找是否存在满足的y
for (int i = 1, j = ak; i <= k; i++) { // j记录(a^k)^x
if (hash.count(j)) return (ll)i * k - hash[j]; // 返回t值
j = (ll)j * ak % p;
}
return -1; // 无解
}
void solve() {
int a, b, m, x0, x; cin >> a >> b >> m >> x0 >> x;
if (x0 == x) {
cout << "YES";
return;
}
int x1 = ((ll)a * x0 + b) % m;
if (a == 0) { // 特判
if (x1 == x || b == x) cout << "YES";
else cout << "NO";
}
else if (a == 1) { // 特判
if (!b) cout << (x == x1 ? "YES" : "NO");
else {
// 求不定方程(n-1)b + mp = t - X0的最小正整数解
int x, y;
exgcd(b, m, x, y);
x = ((ll)x * (x - x1) % m + m) % m; // 保证x是正数
cout << (~x ? "YES" : "NO");
}
}
else {
int C = (ll)b * qpow(a - 1, m - 2, m) % m; // b/(a-1)
int A = (x1 + C) % m; // 分母
if (!A) { // 特判A=0
int ans = (-C + m) % m;
cout << (ans == x ? "YES" : "NO");
}
else {
int B = (x + C) % m; // 分子
int ans = bsgs(a, (ll)B * qpow(A, m - 2, m) % m, m);
cout << (~ans ? "YES" : "NO");
}
}
}
int main() {
solve();
}
有 n n n堆石头,其中第 i i i堆有 a i a_i ai个.每轮A和B选择一个区间 [ l , r ] [l,r] [l,r]在其上做Nim游戏,A先手.每个玩家每次可从任一堆中取走任意数量的石头,无法操作者败.两人都采取最优策略.现有操作:选择一个区间 [ l , r ] [l,r] [l,r],令其中每堆的石头数 + = x +=x +=x.
第一行输入两个整数 n , m ( 1 ≤ n ≤ 1 e 5 , 1 ≤ m ≤ 1 e 5 ) n,m\ \ (1\leq n\leq 1\mathrm{e}5,1\leq m\leq 1\mathrm{e}5) n,m (1≤n≤1e5,1≤m≤1e5),分别表示石头堆数、操作数.第二行输入 n n n个整数 a 1 , ⋯ , a n ( 1 ≤ a i ≤ 1 e 9 ) a_1,\cdots,a_n\ \ (1\leq a_i\leq 1\mathrm{e}9) a1,⋯,an (1≤ai≤1e9).接下来 m m m行每行输入一个操作,格式如下:① 1 l r x 1\ l\ r\ x 1 l r x,表示令区间 [ l , r ] [l,r] [l,r]中每堆的石头数 + = x +=x +=x;② 2 l r 2\ l\ r 2 l r,表示询问选择 [ l , r ] [l,r] [l,r]做Nim游戏,B是否必胜,若是则输出"Yes";否则输出"No".数据保证操作中 1 ≤ l ≤ r ≤ n , 1 ≤ x ≤ 1 e 4 1\leq l\leq r\leq n,1\leq x\leq 1\mathrm{e}4 1≤l≤r≤n,1≤x≤1e4.
显然可用BIT实现区间修改和区间查询.因选择区间 [ l , r ] [l,r] [l,r]做Nim游戏时,若其中石头数的异或和为 0 0 0,先手必败,即后手必胜,故操作②只需考察 [ l , r ] [l,r] [l,r]中石头数的异或和,但这无法用BIT快速查询.
考虑线性基.注意到若能不将 a [ i ] a[i] a[i]插入线性基,则 a [ i ] a[i] a[i]与线性基中某些元素异或和为零,可检查 [ l , r ] [l,r] [l,r]中的元素是否都能插入线性基,若至少存在一个元素不能插入线性基,则后手必胜;否则后手必败.
const int MAXN = 1e5 + 5;
struct FenwickTree {
int n; // 数组长度
ll a[MAXN]; // 原数组,下标从1开始
ll BIT1[MAXN]; // 维护差分数组diff[]的前缀和
ll BIT2[MAXN]; // 维护i*diff[i]的前缀和
int lowbit(int x) { return x & (-x); }
void add(ll BIT[], int x, ll c) { // BIT[x]+=c
for (int i = x; i <= n; i += lowbit(i)) BIT[i] += c;
}
ll sum(ll BIT[], int x) { // 求[1...x]的前缀和
ll res = 0;
for (int i = x; i; i -= lowbit(i)) res += BIT[i];
return res;
}
ll get_pre(int x) { // 求a[1...x]的前缀和
return sum(BIT1, x) * (x + 1) - sum(BIT2, x);
}
void modify(int l, int r, ll c) { // 区间修改:a[l...r]+=c
add(BIT1, l, c), add(BIT2, l, c * l);
add(BIT1, r + 1, -c), add(BIT2, r + 1, -c * (r + 1));
}
ll query(int l, int r) { // 区间查询:求a[l...r]的和
return get_pre(r) - get_pre(l - 1);
}
void build() { // 对原数组建BIT
for (int i = 1; i <= n; i++) {
ll diff = a[i] - a[i - 1];
add(BIT1, i, diff), add(BIT2, i, diff * i);
}
}
}bit;
bool insert(int x, vi& base) { // 将数x插入线性基base,返回插入是否成功
for (int i = 31; i >= 0; i--) {
if (x >> i & 1) {
if (base[i]) x ^= base[i];
else {
base[i] = x; // 插入线性基
return true; // 插入成功
}
}
}
return false; // 插入失败
}
void solve() {
int m; cin >> bit.n >> m;
for (int i = 1; i <= bit.n; i++) cin >> bit.a[i];
bit.build();
while (m--) {
int op, l, r; cin >> op >> l >> r;
if (op == 1) {
int x; cin >> x;
bit.modify(l, r, x);
}
else {
vi base(35); // 线性基
bool ok = false;
for (int i = l; i <= r; i++) {
int a = bit.query(i, i); // a[i]
if (!insert(a, base)) { // 注意是后手必胜
ok = true;
break;
}
}
cout << (ok ? "Yes" : "No") << endl;
}
}
}
int main() {
solve();
}