ZR省选十连测
#1
A
考虑其等价于把
可以使用容斥加分治 解决其。
B
太难了,补不动。
C
考虑
这里只考虑
思考我们需要记录前缀合并情况里
如果随机序列
点击查看代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef pair <int, int> pii;
const long long INF = 0x3f3f3f3f3f3f3f3f;
long long dp[200010][5];
vector <pii> G[200010];
int n, k;
long long f[2010][2];
void dfs(int x, int last) {
int son = 0;
for (auto it : G[x]) {
int v = it.fi, w = it.se;
if (v == last) continue;
dfs(v, x), son++;
}
int S = min(2001, son << 1 | 1);
for (int i = 0; i <= S; i++) {
f[i][0] = f[i][1] = -INF;
}
random_shuffle(G[x].begin(), G[x].end());
int be = S >> 1;
f[be][0] = 0;
for (auto it : G[x]) {
int v = it.fi, w = it.se;
if (v == last) continue;
long long lst[2] = {-INF, -INF};
for (int i = 0; i < S; i++) {
long long cur[2] = {f[i][0], f[i][1]};
for (int j = 0; j < 2; j++) {
f[i][j] += max(dp[v][0], dp[v][k - 1] + w);
f[i][j] = max(f[i][j], lst[j] + dp[v][0] + w);
f[i][j] = max(f[i][j], f[i + 1][j] + dp[v][k - 2] + w);
if (k == 4) f[i][j] = max(f[i][j], cur[j ^ 1] + dp[v][1] + w);
}
lst[0] = cur[0], lst[1] = cur[1];
}
}
dp[x][0] = f[be][0];
dp[x][1] = f[be + 1][0];
dp[x][k - 1] = be ? f[be - 1][0] : -INF;
if (k == 4) dp[x][2] = f[be][1];
}
int main() {
srand((int)time(NULL));
scanf("%d%d", &n, &k);
for (int i = 1; i < n; i++) {
int x, y, w; scanf("%d%d%d", &x, &y, &w);
G[x].push_back(mp(y, w));
G[y].push_back(mp(x, w));
}
dfs(1, 1);
printf("%lld\n", dp[1][0]);
return 0;
}
#4
A
一个诈骗题,考虑对每个点向外BFS寻找非平凡回路,只要
点击查看代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
const int Maxn=5000;
const int Inf=0x3f3f3f3f;
int n;
std::vector<int> g[Maxn+5];
int dis[Maxn+5];
bool vis[Maxn+5];
int qu[Maxn+5],qu_f,qu_t;
int init_bfs(int S){
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
dis[S]=0,vis[S]=1;
qu_f=1,qu_t=0;
qu[++qu_t]=S;
while(qu_f<=qu_t){
int u=qu[qu_f++];
for(int v:g[u]){
if(!vis[v]){
dis[v]=dis[u]+1;
vis[v]=1;
qu[++qu_t]=v;
}
else if(dis[u]<=dis[v]){
return dis[u]+1;
}
}
}
return -1;
}
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++){
static char s[Maxn+5];
scanf("%s",s+1);
int len=0;
while(s[++len]!='\0');
len--;
for(int j=1;j<i;j++){
if(s[j]=='1'){
g[i].push_back(j),g[j].push_back(i);
}
}
}
for(int i=1;i<=n;i++){
printf("%d\n",init_bfs(i));
}
return 0;
}
B
#5
A
写做
考虑我们只要每次每次后缀加入一个数动态维护
B
考虑有结论
结论一:当
,有 ,那么即最小值异或对只会出现在相邻的
结论二:当
, ,当有这两个结论时我们就可以做
我们考虑当
考虑实际上加入一个数时其
点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 1000005
using std::set;
set<int>A;
int V,n;
#define inf (1ll << 21)
int mn = inf;
ll ans[inf];
int main(){
scanf("%d%d",&V,&n);
for(int i = 0;i < inf;++i)
ans[i] = inf;
for(int i = 1;i <= n;++i){
int opt,x;
scanf("%d%d",&opt,&x);
if(opt == 1){
A.insert(x);
set<int>::iterator it = A.lower_bound(x);
set<int>::iterator cur = it;
if(it != A.begin()){
-- it;
// std::cout<<"("<<*it<<" "<<x<<")"<<"\n";
mn = std::min(mn,x - *it);
for(int i = 0;i <= mn;++i)
ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
}
it = ++cur;
if(it != A.end()){
mn = std::min(mn,*it - x);
// std::cout<<"("<<x<<" "<<*it<<")"<<"\n";
for(int i = 0;i <= mn;++i)
ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
}
// std::cout<<mn<<"\n";
}else{
if(x > mn)
std::cout<<mn<<"\n";
else
std::cout<<ans[x]<<"\n";
}
}
}
结论三:考虑到答案的最终贡献方式,一定是让所有相邻对的某一位的后
位归 ,即可贡献维护的答案 不超过 个,考虑直接对这 个维护即可。
点击查看代码
ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
}
it = ++cur;
if(it != A.end()){
mn = std::min(mn,*it - x);
// std::cout<<"("<<x<<" "<<*it<<")"<<"\n";
for(int i = 0;i <= mn;++i)
ans[i] = std::min(ans[i],1ll * (i + *it) ^ (i + x)),ans[i] = (i == 0) ? ans[i] : std::min(ans[i - 1],ans[i]);
}
// std::cout<<mn<<"\n";
}else{
if(x > mn)
std::cout<<mn<<"\n";
else
std::cout<<ans[x]<<"\n";
C
考虑每次维护中间块
然后考虑删除时直接暴力重构。
#6
给我心态打崩了。
坐牢,签到都没签上。
A
怎么开局一直想着枚举左端点。
考虑强制钦定最小值的位置,设
考虑其对于一个询问
考虑对于所有
(借一下rsx的代码)
#6 A
#include <bits/stdc++.h>
const int MAXN = 1e5 + 10;
using std::cin;
using std::cout;
template <typename T>
inline T min(const T &x, const T &y) {
return x < y ? x : y;
}
template <typename T>
struct Fenwick_Tree {
int limit;
T t[MAXN];
void add(int x, T y) {
for (; x <= limit; x += x & -x) {
t[x] += y;
}
return;
}
T sum(int x) {
T ret = 0;
for (; x; x -= x & -x) {
ret += t[x];
}
return ret;
}
void build(int _N) {
limit = _N;
}
};
Fenwick_Tree <int> cyc;
int N, L, R, A[MAXN], Pos[MAXN];
long long K[MAXN], B[MAXN];
void add(long long *qjy, int l, int r, long long v) {
qjy[l] += v;
qjy[r + 1] -= v;
}
int main() {
std::ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> N >> L >> R;
for (int i = 1; i <= N; ++i) {
cin >> A[i];
Pos[A[i]] = i;
}
cyc.build(N);
for (int i = 1; i <= N; ++i) {
cyc.add(Pos[N - i + 1], 1);
int Tk = cyc.sum(Pos[N - i + 1]);
int Tmp = min(Tk, i - Tk + 1);
add(K, 1, Tmp, 1);
add(B, Tmp + 1, i - Tmp, Tmp);
add(K, i - Tmp + 1, i, -1);
add(B, i - Tmp + 1, i, i + 1);
}
for (int i = 1; i <= N; ++i) {
K[i] += K[i - 1];
B[i] += B[i - 1];
}
long long SUM = 0;
for (int i = L; i <= R; ++i) {
SUM ^= K[i] * i + B[i];
}
cout << SUM << '\n';
return 0;
}
B
考虑对格子上的史莱姆进行
则有
于是可以直接高斯消元得到
#6 B 40分
#include<bits/stdc++.h>
#define ll long long
#define N 105
#define mod 998244353
#define I4 748683265
#define pii std::pair<int,int>
#define mp std::make_pair
int dx[] = {-1,0,1,-0};
int dy[] = {0,-1,0,1};
int n,X[N],Y[N],a[N][N],T[N],ans;
#define mpi std::map<pii,int>
mpi P,C;
inline ll qpow(ll a,ll b){
ll res = 1;
while(b){
if(b & 1)res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
inline void guass(int n){
for(int i = 1;i <= n;++i){
int pos = i;
for(int j = i;j <= n;++j)
if(a[j][i]){
pos = j;
break;
}
if(pos ^ i)std::swap(a[i],a[pos]);
int w = qpow(a[i][i],mod - 2);
for(int j = 1;j <= n;++j){
if(j == i)continue;
int t = 1ll * a[j][i] * w % mod;
for(int k = i;k <= n + 1;++k)
a[j][k] = ((a[j][k] - 1ll * t * a[i][k] % mod) % mod + mod) % mod;
}
}
for(int i = 1;i <= n;++i)
a[i][n + 1] = 1ll * (1ll * a[i][n + 1] * (mod - 1) % mod * qpow(a[i][i],mod - 2)) % mod;
}
inline void solve(){
for(int i = 1;i <= n;++i){
// std::cout<<"DEL "<<i<<std::endl;
for(int j = 0;j < 4;++j){
int x = X[i] + dx[j],y = Y[i] + dy[j];
// std::cout<<x<<" "<<y<<"\n";
if(P.find(mp(x,y)) == P.end())continue;
a[i][P[mp(x,y)]] = (I4) % mod;
}
a[i][i] = mod - 1;
a[i][n + 1] = T[i];
}
guass(n);
for(auto i : C){
int sx = i.first.first,sy = i.first.second,res = 0;
// std::cout<<sx<<" "<<sy<<std::endl;
for(int j = 0;j < 4;++j){
int nx = sx + dx[j];
int ny = sy + dy[j];
if(P.find(mp(nx,ny)) == P.end())continue;
res = (res + a[P[mp(nx,ny)]][n + 1]) % mod;
}
ans = ans ^ (1ll * I4 * res % mod);
}
std::cout<<ans<<"\n";
}
int main(){
scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%d%d%d",&X[i],&Y[i],&T[i]);
P[mp(X[i],Y[i])] = i;
}
for(int i = 1;i <= n;++i)
for(int j = 0;j < 4;++j){
int x = X[i] + dx[j],y = Y[i] + dy[j];
if(P.find(mp(x,y)) == P.end())C[mp(x,y)] = 1;
}
solve();
}
当
但是我发现有份代码直接对矩阵随机打乱然后记录有元素的值,跑的也很快。
#6 B 60分
inline void guass(int n){
std::random_shuffle(a+1,a+n+1);
for(R int i=1;i<=n;++i)
for(R int j=1;j<=n+1;++j) if(a[i][j]) mw[i].insert(j);
for(R int i=1;i<=n;++i){
R int j=i;
for(;j<=n;++j) if(a[j][i]) break;
if(j^i) std::swap(a[i],a[j]),std::swap(mw[i],mw[j]);
R int ha=qpow(a[i][i],P-2);
for(j=1;j<=n;++j){
if(j==i) continue;
if(mw[j].find(i)==mw[j].end())continue;
R int qc=1LL*(P-a[j][i])*ha%P;
for(auto k:mw[i]){
if(!a[j][k]) mw[j].insert(k);
a[j][k]=(a[j][k]+1LL*qc*a[i][k])%P;
if(!a[j][k]) mw[j].erase(k);
}
}
}
for(R int i=1;i<=n;++i){
a[i][n+1]=(a[i][n+1]*(P-1LL)%P*qpow(a[i][i],P-2))%P;
}
}
考虑矩阵情况,可以直接手动消元把除第一列的元素都用第一列表示,最后使用最后一列的关系对其消元,这样只有
#7
A
考虑一次操作二会改变奇偶性。
一定是先操作二一次,然后再检查子区间是否有全偶区间即可。
当带0时,其把序列划分位若干子区间。
考虑扫描线即可。
找到前面第一个不是偶数的子区间即可。
B
但是随机太好了。
被某些根号算法草爆了。
这里提供一个线段树覆盖代替原本的暴力并查集的做法。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define N 15005
int n,m,q,mx,a[N];
int sum[35000];
#define mid ((l + r) >> 1)
#define ls(x) (x << 1)
#define rs(x) (x << 1 | 1)
using std::bitset;
using std::array;
using std::vector;
bitset<35000>tag;
vector<array<int,4>>M;
inline void cov(int u,int l,int r,int tl,int tr){
if(tag[u])return ;
if(tl <= l && r <= tr){tag[u] = 1,sum[u] = r - l + 1;return ;}
if(tl <= mid)
cov(ls(u),l,mid,tl,tr);
if(tr > mid)
cov(rs(u),mid + 1,r,tl,tr);
tag[u] = tag[ls(u)] & tag[rs(u)],sum[u] = sum[ls(u)] + sum[rs(u)];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= n;++i){
scanf("%d",&a[i]);
M.push_back({i,i,a[i],0});
}
for(int i = 1;i <= m;++i){
int l,r,x;
scanf("%d%d%d",&l,&r,&x);
M.push_back({l,r,x,i});
}
std::sort(M.begin(), M.end(), [&](array<int, 4> x, array<int, 4> y) { return x[2] < y[2]; });
while(q -- ){
int l1,r1,l2,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
memset(sum,0,sizeof(sum)),tag.reset();
ll ans = 0;
int lst = 0;
for (auto &p : M) if (!p[3] || p[3] >= l1 && p[3] <= r1) {
int l = std::max(l2, p[0]), r = std::min(r2, p[1]);
if (l <= r) cov(1, 1, n, l, r);
ans += 1ll * p[2] * (sum[1] - lst);
if ((lst = sum[1]) == r2 - l2 + 1) break;
}
printf("%lld\n", ans);
}
}
#8
A
考虑
考虑限制很紧,一不小心就会大于
考虑只有两种情况:
对着检查即可。
点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N 2000005
#define mod 998244353
char s[N],t[N];
int n;
int T;
bool pre[N],suf[N];
bool check(char a,char b){
return a == '?' || a == b;
}
ll ans = 0;
inline void calc(char a,char b,char c){
int now = 1;
for(int i = 1;i <= (n << 1) + 1;++i)
if(i & 1)
now = now * check(s[i],a) * check(t[i],c) % mod;
else
now = now * check(s[i],b) * (check(t[i],a) + check(t[i],b)) % mod;
ans = (ans + now) % mod;
now = 1;
for(int i = 1;i <= (n << 1) + 1;++i)
if(i & 1)
now = now * check(t[i],a) * check(s[i],c) % mod;
else
now = now * check(t[i],b) * (check(s[i],a) + check(s[i],b)) % mod;
ans = (ans + now) % mod;
pre[0] = suf[2 * n + 2] = 1;
for(int i = 1;i <= (n << 1) + 1;++i){
if(i & 1)
pre[i] = pre[i - 1] & check(s[i],a) & check(t[i],b);
else
pre[i] = pre[i - 1] & check(s[i],c) & check(t[i],c);
}
for(int i =(n << 1) + 1;i >= 1;--i){
if(i & 1)
suf[i] = suf[i + 1] & check(s[i],b) & check(t[i],a);
else
suf[i] = suf[i + 1] & check(s[i],c) & check(t[i],c);
}
for(int i = 1;i <= (n << 1) + 1;i += 2)
ans += (i == ((n << 1) + 1)) ? - (pre[i] & suf[i + 1]) : pre[i] & suf[i + 1] ;
}
int main(){
scanf("%d",&T);
while(T -- ){
ans = 0;
scanf("%d%s%s",&n,s + 1,t + 1);
calc('A','B','C');
calc('A','C','B');
calc('B','A','C');
calc('B','C','A');
calc('C','A','B');
calc('C','B','A');
std::cout<<ans<<"\n";
}
}
/*
2
?????
?????
*/
B
考虑树上枚举
考虑当
那么直接对询问扫描线即可。
考虑只要枚举相邻的
#10
C
先考虑菊花的做法,发现其等价于给定点权,一条边的代价为
其可以使用
考虑改为任意树,可以使用点/边分治,将路径改为上述形式解决。
每一轮,每点均找到异子树内的最小权边,共有
使用边分治更好处理。
点击查看代码
//晦暗的宇宙,我们找不到光,看不见尽头,但我们永远都不会被黑色打倒。——Quinn葵因
#include<bits/stdc++.h>
#define ll long long
#define N (int)2e6
using std::vector;
using std::pair;
#define pii pair<int,int>
#define mp std::make_pair
int head[N];
struct P{
int to,next,w;
}E[N * 20];
int cnt = 1;
inline void add(int u,int v,int w){
E[++cnt].to = v;
E[cnt].next = head[u];
E[cnt].w = w;
head[u] = cnt;
}
inline void adde(int u,int v,int w){
add(u,v,w);
add(v,u,w);
}
vector<pii>G[N];
int m;
inline void reb(int u,int fa){
int lst = 0;
for(auto vi : G[u]){
int v = vi.first;
int w = vi.second;
if(v == fa)continue;
if(!lst){
adde(u,v,w);
lst = u;
}else{
adde(lst,++m,0);
adde(m,v,w);
lst = m;
}
reb(v,u);
}
}
int siz[N],re,minn,sum;
int vis[N];
inline void getroot(int u,int fa){
siz[u] = 1;
for(int i = head[u];i;i = E[i].next){
int v = E[i].to;
if(v == fa || vis[i])continue;
getroot(v,u);
siz[u] += siz[v];
if(std::max(siz[v],sum - siz[v]) < minn)
minn = std::max(siz[v],sum - siz[v]),re = i;
}
}
ll dis[N];
int ent;
struct nod {
int u,v;
ll w;
nod(){}
nod(int _u,int _v,ll _w){u = _u,v = _v,w = _w;}
}e[N * 40];
bool operator < (nod A,nod B){
return A.w < B.w;
}
int fa[N];
inline int find(int x){return (x == fa[x]) ? x : fa[x] = find(fa[x]);}
pair<ll,int>Vec[3][N];
int sig[3];
inline void calc(int u,int tag,int fa){
Vec[tag][++sig[tag]] = mp(dis[u],u);
for(int i = head[u];i;i = E[i].next){
int v = E[i].to;
int w = E[i].w;
if(v == fa || vis[i])continue;
dis[v] = dis[u] + w;
calc(v,tag,u);
}
}
inline ll llabs(ll x){return x > 0 ? x : -x;}
inline void solve(int u){
if(sum == 1)return;
minn = 1e9;getroot(u,0);
vis[re] = vis[re ^ 1] = 1;
// std::cout<<u<<" "<<sum<<" "<<re<<"\n";
int x = E[re].to,y = E[re ^ 1].to;
sig[1] = sig[2] = 0;
dis[x] = E[re].w;calc(x,1,0);
dis[y] = 0;calc(y,2,0);
std::sort(Vec[1] + 1,Vec[1] + sig[1] + 1);
std::sort(Vec[2] + 1,Vec[2] + sig[2] + 1);
for(int i=1,j=sig[2];i<=sig[1];i++) {
while(j&&Vec[2][j].first>-Vec[1][i].first) j--;
if(j+1<=sig[2]) e[++ent]=nod(Vec[1][i].second,Vec[2][j+1].second,llabs(Vec[1][i].first+Vec[2][j+1].first));
if(j) e[++ent]=nod(Vec[1][i].second,Vec[2][j].second,llabs(Vec[1][i].first+Vec[2][j].first));
}
std::swap(sig[1],sig[2]);
for(int i=1;i<=std::max(sig[1],sig[2]);i++) swap(Vec[1][i],Vec[2][i]);
for(int i=1,j=sig[2];i<=sig[1];i++) {
while(j&&Vec[2][j].first>-Vec[1][i].first) j--;
if(j+1<=sig[2]) e[++ent]=nod(Vec[1][i].second,Vec[2][j+1].second,llabs(Vec[1][i].first+Vec[2][j+1].first));
if(j) e[++ent]=nod(Vec[1][i].second,Vec[2][j].second,llabs(Vec[1][i].first+Vec[2][j].first));
}
int now = sum - siz[x];
sum = siz[x];
solve(x);
sum = now;
solve(y);
}
int n;
int main(){
// freopen("q.in","r",stdin);
// freopen("q.ans","w",stdout);
scanf("%d",&n);
m = n;
for(int i = 1;i < n;++i){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
G[x].emplace_back(y,w);
G[y].emplace_back(x,w);
}
reb(1,0);
sum = m;
solve(1);
std::sort(e + 1,e + ent + 1);
ll ans = 0;
for(int i = 1;i <= m;++i)fa[i] = i;
for(int i = 1;i <= ent;++i){
// std::cout<<e[i].u<<" "<<e[i].v<<" "<<e[i].w<<"\n";
if(find(e[i].u) ^ find(e[i].v)){
fa[fa[e[i].u]] = fa[e[i].v];
ans += e[i].w;
}
}
std::cout<<ans<<"\n";
}
本文作者:fhq_treap
本文链接:https://www.cnblogs.com/dixiao/p/15942900.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】