来自学长的馈赠1
首先感谢学长
A. Alice
打表好题, 通过打表可以发现就是判断两个数\(lowbit\)是否相等
实测\(cin\), \(cout\)不如\(scanf\)和\(printf\)快(血的教训)
code
#include<cstring>
#include<cstdio>
using namespace std;
int lowbit(int x){return x & -x;}
int main(){
int T;scanf("%d",&T);
for(int i = 1; i <= T; ++i){
int a, b;scanf("%d%d",&a,&b);
if(lowbit(a) == lowbit(b))printf("B\n");
else printf("A\n");
}
return 0;
}
B. Box
题解写的很好,直接粘过来了
里面那个容易证明,其实是\(minmax\)容斥
\(m + m / (m + 1) * m\)和后面那个类似的式子,可以这样理解一下
放下\(m\)个当前颜色球,会有\(m + 1\)个空位,有\(m\)个对答案有贡献,一共需要插进去\(m\)个。
关于线性求逆优化,简单来说就是一个前缀积,类似求阶乘逆元那样,具体看代码吧
code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod = 998244353;
const int maxn = 2e7 + 55;
int fac[maxn], finv[maxn], s[maxn], a[maxn],iv[maxn], sv[maxn], n, m;
int qpow(int x, int y){
int ans = 1;
for(;y ; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
int c(int n, int m){return 1ll * fac[n] * finv[m] % mod * finv[n - m] % mod;}
int main(){
scanf("%d%d", &n, &m);
fac[0] = 1;
for(int i = 1; i <= n; ++i)
fac[i] = 1ll * fac[i - 1] * i % mod;
finv[n] = qpow(fac[n], mod - 2);
for(int i = n - 1; i >= 1; --i)finv[i] = 1ll * finv[i + 1] * (i + 1) % mod;
finv[0] = 1;
for(int i = 1; i <= n; ++i)a[i] = (1ll * m * i + 1) % mod;
s[0] = 1;
for(int i = 1; i <= n; ++i)s[i] = 1ll * a[i] * s[i - 1] % mod;
sv[n] = qpow(s[n], mod - 2);
for(int i = n - 1; i >= 1; --i)sv[i] = 1ll * sv[i + 1] * a[i + 1] % mod;
iv[1] = sv[1];
for(int i = 2; i <= n; ++i)iv[i] = 1ll * sv[i] * s[i - 1] % mod;
int ans = 0;
for(int i = 1; i <= n; ++i){
if(i & 1)ans = (ans + (1ll * c(n, i) * ((1ll * m * i % mod + 1ll * m * i % mod * iv[i] % mod * m % mod * (n - i) % mod) % mod) % mod) )% mod;
else ans = ((ans - 1ll * c(n, i) * ((1ll * m * i % mod + 1ll * m * i % mod * iv[i] % mod * m % mod * (n - i) % mod) % mod) % mod ) % mod + mod ) % mod;
}
printf("%d\n", ans);
return 0;
}
C. Common
这是一道常规套路题
确实比较套路
默认\(a[0][0] = 1\), 那么如果令\(a[-b[i]][-c[i]] = 1\)的话,对于任意\(a[b[j]][c[j]]\)他的值其实是\(a[b[i]+b[j]][c[i]+c[j]]\)
然后就可以把\(a[-b[i]][-c[i]]\)全加一,然后按照式子递推一遍即可
code
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn = 4055;
const int o = 2005;
const int mod = 998244353;
int rem[maxn][maxn];
int n, t1, t2, t3, mb, mc;
int b[1000005], c[1000005];
int main(){
scanf("%d%d%d%d", &n, &t1, &t2, &t3);
for(int i = 1; i <= n; ++i)scanf("%d", &b[i]);
for(int i = 1; i <= n; ++i)scanf("%d", &c[i]);
for(int i = 1; i <= n; ++i)mb = max(mb, b[i]);
for(int i = 1; i <= n; ++i)mc = max(mc, c[i]);
for(int i = 1; i <= n; ++i)++rem[o - b[i]][o - c[i]];
for(int i = o - mb; i <= o + mb ; ++i){
for(int j = o - mc; j <= o + mc; ++j){
rem[i][j] = (rem[i][j] + 1ll * t1 * rem[i - 1][j] % mod + 1ll * t2 * rem[i][j - 1] % mod + 1ll * t3 * rem[i - 1][j - 1] % mod) % mod;
}
}
int ans = 0;
for(int i = 1; i <= n; ++i)ans = (ans + rem[o + b[i]][o + c[i]]) % mod;
printf("%d\n", ans);
return 0;
}
D. Do not ak
分块+卡常,洛谷至今没卡过
题解看洛谷吧P5046
code
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#define block(x) (((x) - 1) / len + 1)
#define bl(x) (((x) - 1) * len + 1)
#define br(x) min(n, x * len)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 55;
const int maxb = 505;
inline int read(){
int x = 0; char c;c = getchar();
while(c < '0' || c > '9')c = getchar();
while(c >= '0' && c <= '9')x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
return x;
}
int n, m, a[maxn], len, pre[maxn], suf[maxn], pres[maxn], tong[maxn], cntl[maxb][maxn], cntr[maxb][maxn];
ll ansl[maxb][maxn], ansr[maxb][maxn];
struct note{
int val, pos;
friend bool operator < (note x, note y){
return x.val < y.val;
}
}b[maxn];
struct tree{
int t[maxn];
int lowbit(int x){return x & -x;}
void add(int x, int d){while(x <= n){t[x] += d;x += lowbit(x);}}
int query(int x){int ans = 0;while(x){ans += t[x]; x -=lowbit(x);} return ans;}
}T;
int x[maxn], y[maxn], cx, cy;
int merg(){
int p1 = 1, p2 = 1, ans = 0;
while(p1 <= cx && p2 <= cy)
if(x[p1] < y[p2]) ++p1; else ans += cx - p1 + 1, ++p2;
return ans;
}
int main(){
n = read(), m = read(); len = 500;
for(register int i = 1; i <= n; ++i)a[i] = read();
for(register int i = 1; i <= n; ++i)b[i].val = a[i], b[i].pos = i;
int ks = block(n);
for(register int i = 1; i <= ks; ++i){
int l = bl(i), r = br(i);
sort(b + l, b + r + 1);
for(register int j = l; j <= r; ++j)pre[j] = j - l - T.query(a[j]), T.add(a[j], 1);
for(register int j = l; j <= r; ++j)T.add(a[j], -1);
for(register int j = r; j >= l; --j)suf[j] = T.query(a[j]), T.add(a[j], 1);
for(register int j = l; j <= r; ++j)T.add(a[j], -1);
pres[l] = pre[l];
for(register int j = l + 1; j <= r; ++j)pres[j] = pre[j] + pres[j - 1];
}
for(register int i = 1, nb = 1; i <= n; ++i){
++tong[a[i]];
if(i == br(nb)){
for(register int j = 1; j <= n; ++j)cntl[nb][j] = cntl[nb][j - 1] + tong[j];
for(register int j = n; j >= 1; --j)cntr[nb][j] = cntr[nb][j + 1] + tong[j];
++nb;
}
}
for(register int i = 1; i <= ks; ++i)
for(register int j = bl(i); j <= n; ++j)
ansr[i][j] = ansr[i][j - 1] + cntr[block(j) - 1][a[j] + 1] - cntr[i - 1][a[j] + 1] + pre[j];
for(register int i = 1; i <= ks; ++i)
for(register int j = br(i); j >= 1; --j)
ansl[i][j] = ansl[i][j + 1] + cntl[i][a[j] - 1] - cntl[block(j)][a[j] - 1] + suf[j];
ll ans = 0;
for(register int ask = 1; ask <= m; ++ask){
int l, r; l = read(), r = read();
l ^= ans; r ^= ans;
if(l > r)swap(l, r);
ans = 0;
cx = cy = 0;
int kl = block(l), kr = block(r);
if(kl == kr){
for(register int i = bl(kl); i <= br(kl); ++i)
if(l <= b[i].pos && b[i].pos <= r)y[++cy] = b[i].val;
else if(b[i].pos < l)x[++cx] = b[i].val;
ans = pres[r] - (l == bl(kl) ? 0 : pres[l - 1]) - merg();
}else{
ans = ansl[kr - 1][l] + ansr[kl + 1][r] - ansl[kr - 1][bl(kl + 1)];
for(register int i = bl(kl); i <= br(kl); ++i)if(b[i].pos >= l)x[++cx] = b[i].val;
for(register int i = bl(kr); i <= br(kr); ++i)if(b[i].pos <= r)y[++cy] = b[i].val;
ans += merg();
}
printf("%lld\n",ans);
}
return 0;
}