2022NOIP A层联测32
A. 行走
按照颜色考虑,然后发现是 \(excrt\)
考场重新发明 \(excrt\)
但是炸了 \(long long\)
而且 \(k\) 没有取到最小整数解
code
#include<bits/stdc++.h>
using namespace std;
typedef __int128_t ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
ll read(){
ll x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 250005;
int n, m, s[maxn];
vector<ll>a[maxn], b[maxn], t, lc;
ll exgcd(ll a, ll &x, ll b, ll &y){
if(b == 0){x = 1; y = 0; return a;}
ll g = exgcd(b, y, a % b, x);
y = y - a / b * x; return g;
}
void sol(ll col){
ll x, lcm;
x = a[col].back(), lcm = b[col].back();
a[col].pop_back(); b[col].pop_back();
for(int i = 0; i < n - 1; ++i){
ll k1, k2; ll g = exgcd(lcm, k1, b[col].back(), k2);
ll c = x - a[col].back();
if(c % g)return;
lcm /= g; k2 = (k2 % lcm * (c / g) % lcm + lcm) % lcm;
lcm = lcm * b[col].back();
x = (k2 * b[col].back() % lcm + lcm + a[col].back()) % lcm;
a[col].pop_back(); b[col].pop_back();
}
x = (x % lcm + lcm) % lcm;
t.push_back(x); lc.push_back(lcm);
}
ll calc(ll l){
ll ans = 0;
int s = t.size();
for(int i = 0; i < s; ++i)ans += l / lc[i] + (l % lc[i] > t[i]);
return ans;
}
ll l, r;
int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
n = read(), m = read(), l = read(), r = read();
--l; --r;
for(int i = 1; i <= n; ++i){
s[i] = read();
for(int j = 0; j < s[i]; ++j){
int col = read();
a[col].push_back(j);
b[col].push_back(s[i]);
}
}
for(int i = 0; i <= m; ++i)if((int)b[i].size() == n)sol(i);
printf("%lld\n",(long long)calc(r) - (long long )calc(l - 1));
return 0;
}
B. 鸟之诗
简单容斥一下
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
ll read(){
ll x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 2000006;
const int mod = 998244353;
ll qpow(ll x, ll y){
if(x < 0)return 0;
ll ans = 1;
for(; y; y >>= 1, x = 1ll * x * x % mod)if(y & 1)ans = 1ll * ans * x % mod;
return ans;
}
ll n, m, a[maxn], b[maxn];
int main(){
freopen("air.in","r",stdin);
freopen("air.out","w",stdout);
m = read(), n = read() % (mod - 1);
for(int i = 1; i <= m; ++i)a[i] = read();
for(int i = 1; i <= m; ++i)b[i] = read();
ll ans = 1;
for(int i = 1; i <= m; ++i){
if(a[i] > b[i])ans = 0;
if(a[i] < b[i]){
ans = 1ll * ans * (((qpow(b[i] - a[i] + 1, n) - 2 * qpow(b[i] - a[i], n) + qpow(b[i] - a[i] - 1, n)) % mod + mod ) % mod) % mod;
}
}
printf("%lld\n",ans);
return 0;
}
C. 核心共振
一看这种题就直接放弃了。。。。
最后时间不够,暴力都没打对
粘一下题解,感觉挺妙的
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
ll read(){
ll x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
int mod, p;
const int maxn = 2e7 + 5555;
int fac[maxn], inv[maxn];
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;
}
void init(int mx){
fac[0] = inv[0] = 1; for(int i = 1; i <= mx; ++i)fac[i] = 1ll * fac[i - 1] * i % mod;
inv[mx] = qpow(fac[mx], mod - 2); for(int i = mx - 1; i >= 1; --i)inv[i] = 1ll * inv[i + 1] * (i + 1) % mod;
}
int c(ll n, ll m) {
if(n < m || n < 0 || m < 0)return 0;
if(n >= p || m >= p)return 1ll * c(n / p, m / p) * c(n % p, m % p) % mod;
return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;
}
int f(ll n, ll m){
if(m < p){
int ans = 0;
for(int i = 0; i <= m; ++i)ans = (ans + c(n, i)) % mod;
return ans;
}
int ans = 0;
for(int i = 0; i < p; ++i)ans = (ans + c(n % p, i)) % mod;
ans = 1ll * ans * f(n / p, m / p - 1) % mod;
int res = 0;
for(int i = 0; i <= m % p; ++i)res = (res + c(n % p, i)) % mod;
res = 1ll * res * c(n / p, m / p) % mod;
return (ans + res) % mod;
}
ll n, m;
int main(){
freopen("dimension.in","r",stdin);
freopen("dimension.out","w",stdout);
n = read(), m = read(), p = mod = read();
init(mod - 1);
printf("%d\n", (f(n + 1, m + 1) + mod - 1) % mod);
return 0;
}
D. 无双挑战
基本上是点分治板子了
发现 \(dis\) 可加,于是
用树状数组维护一下后缀和即可
题解做法也容易,放在下面
code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
int read(){
int x = 0; char c = getchar();
while(!isdigit(c))c = getchar();
do{x = x * 10 + (c ^ 48); c = getchar();}while(isdigit(c));
return x;
}
const int maxn = 805005;
const int mod = 998244353;
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 n, m, a[maxn];
vector<int>g[maxn];
int si[maxn], mx[maxn];
bool del[maxn];
void dfs(int x, int fa){
si[x] = 1; mx[x] = 0;
for(int v : g[x])if(v != fa && !del[v]){
dfs(v, x); si[x] += si[v]; mx[x] = max(mx[x], si[v]);
}
}
int root, S;
void find(int x, int fa){
mx[x] = max(mx[x], S - si[x]);
if(mx[x] < mx[root])root = x;
for(int v : g[x])if(v != fa && !del[v])find(v, x);
}
void Add(int &x, int y){x += y; if(x >= mod) x -= mod;}
struct BIT{
int t[maxn];
int lowbit(int x){return x & -x;}
void add(int x, int val){
x = m - x + 1;
while(x <= m){
Add(t[x], val);
x += lowbit(x);
}
}
int query(int x){
int ans = 0; x = m - x + 1;
while(x){
Add(ans, t[x]);
x -= lowbit(x);
}
return ans;
}
}T, t;
vector<int> vec, sub;
int dis[maxn];
int ans;
void link(int x, int fa){
for(int v : g[x])if(!del[v] && v != fa){
vec.push_back(v);
sub.push_back(v);
dis[v] = dis[x] + 1;
link(v, x);
}
}
void calc(int root){
dis[root] = 0;
for(int v : g[root])if(!del[v]){
dis[v] = 1; vec.push_back(v); sub.push_back(v); link(v, root);
for(int x : sub)T.add(a[x], dis[x]), t.add(a[x], 1);
for(int x : sub)Add(ans, mod - 1ll * (T.query(a[x] + 1) + 1ll * t.query(a[x] + 1) * dis[x]) % mod * (m - a[x]) % mod);
for(int x : sub) T.add(a[x], mod - dis[x]), t.add(a[x], -1);
sub.clear();
}
t.add(a[root], 1); for(int x : vec)T.add(a[x], dis[x]), t.add(a[x], 1);
Add(ans, 1ll * T.query(a[root] + 1) * (m - a[root]) % mod);
for(int x : vec)Add(ans, 1ll * (T.query(a[x] + 1) + 1ll * t.query(a[x] + 1) * dis[x]) % mod * (m - a[x]) % mod);
t.add(a[root], -1); for(int x : vec) T.add(a[x], mod - dis[x]), t.add(a[x], -1);
vec.clear();
}
void sol(int x){
dfs(x, 0); S = si[x];
root = 0;
find(x, 0);
x = root; calc(x);
del[x] = true;
for(int v : g[x])if(!del[v])sol(v);
}
int main(){
freopen("challenge.in","r",stdin);
freopen("challenge.out","w",stdout);
n = read(), m = read();
for(int i = 1; i <= n; ++i)a[i] = read();
for(int i = 1; i < n; ++i){
int u = read(), v = read();
g[u].push_back(v); g[v].push_back(u);
}
si[0] = mx[0] = mod;
sol(1);
ans = 1ll * ans * qpow(1ll * n * (n - 1) % mod, mod - 2) % mod;
printf("%d\n",ans);
return 0;
}