W
e
l
c
o
m
e
: )

2025 FJCPC 复建 VP

按开题顺序写 \(BCDEFGHIJKLA(D?)\)\(M\) 送的不写

B

首先发现铜铁本质等价(铜铁的转换不影响 \(val\) ),所以考虑枚举最后金和银的数量 \(gold, silver\),那么约束条件为:

\[val=n-4g-s\ge p \]

\[8g+4s\le n \]

那么考虑剩余铁牌全合成同和全不合成情况,每合成一个铜牌那么总牌数减一,即 \(g, s\)\(i\in[g+s+\left \lfloor \frac{(n-8g-4s+1)}{2} \right \rfloor, g+s+(n-8g-4s)]\)\(ans_{i}\) 有 1 的贡献。

拆开下取整得 \([\left \lfloor \frac{(n+1)}{2} \right \rfloor-3g-s, n-7g-3s]\)

我们枚举 \(g\) 时,需要加的区间 \([l, r]\) 随着 \(s\) 的变化,左右端点分别为公差为 1/3 的等差数列。

将区间 +1 操作变为差分,那么对于某个 \(g\) 上述区间的贡献可以相当于一个等差数列下标组 +1,另一个等差数列下标组 -1,二阶差分数组可以解决。

关键代码:

	for(int i=0, x, s0; i<=n; ++i){
		s0=min(n-4*i-p, (n-8*i)/4);if(s0<0) break;
		x=(n+1)/2-3*i;del[0][x-s0]++, del[0][x+1]--;
		x=n-7*i+1;del[1][x-3*s0]--, del[1][x+3]++;
	}
	for(int i=0; i<=n; ++i){
		if(i) del[0][i]+=del[0][i-1];
		if(i>2) del[1][i]+=del[1][i-3];
		ans[i]=del[0][i]+del[1][i];
	}

C

贪心策略不好处理,考虑二分答案。,那么序列可视为 0/1 序列。

只有两个数是比较容易做贪心的,压缩 000 和 001 即可。

关键代码:

bool check(int v){
	int top=0, c[2]={0, 0};
	for(int i=1; i<=n; ++i){
		bool x=a[i]>=v;//printf("%d", x);
		if(!top){t[++top]={1, x};continue;}
		if(t[top].nd==x){
			++t[top].st;
			if((!t[top].nd)&&t[top].st==3) t[top].st=1;
		}
		else{ 
			t[++top]={1, x};
			if(t[top].nd&&top>1&&t[top-1].st==2){
				--top;t[top].st=1;
			}
		}
	}
	for(int i=1; i<=top; ++i) c[t[i].nd]+=t[i].st;
	return c[1]>=c[0];
}

E

等价于 \(\min |\sum (-1)^{i}a_{i}|\)

操作相当于任选一段长度为偶数的区间使系数 \((-1)^i\) 正负翻转

如果翻转 \([l, r]\)\(ans=|sum_{n}-2sum_{r}+2sum_{l-1}|\)\(sum_{i}\) 是带系数的前缀和。

即找到距离 \(2sum_{r}\) 最近的 \(sum_{n}+2sum_{l-1}\),set 维护即可。

最后的答案 \(ans'=\frac{\sum^{n}_{i=1} a_{n}-ans}{2}\), 需要注意注意 \(l, r\) 奇偶性相反。

关键代码:

	for(int i=1; i<=n; ++i){
		int op=i&1;ll p=-2LL*sum[i];
		if(S[op^1].size()){
			auto it=S[op^1].lower_bound(-p);
			if(it!=S[op^1].end()) t=min(t, (*it)+p);
		}S[op].insert(sum[n]+2LL*sum[i-1]);
		if(T[op^1].size()){
			auto it=T[op^1].lower_bound(p);
			if(it!=T[op^1].end()) t=min(t, (*it)-p);
		}T[op].insert(-2LL*sum[i-1]-sum[n]);
	}

F

考虑得到 \(l_i, r_{i}\)\(i\) 号点左右能让它被肘飞的点(默认 \(l_{i}=0, r_{i}=n+1\)

那么即数 \([L, R]\)\(l_{i}<L, R<r_{i}\)\(i\) 的个数,

那么点 \(i\)\([[l_{i}+1, i], [i, r_{i}-1]]\) 的询问有贡献,视为矩形加,询问单点值,扫描线解决。

\(l_{i}, r_i\): 按 \(x_{i}\) 关键字排逆序在线段树上依次插入 \(i, y_{i}\),查询 \(l_{i}\) 即找到 \([1, i]\) 最右边 \(y_x>y_{i}\) 的部分并返回,\(r_i\) 同理,线段树二分即可。

关键代码:

int queryL(int k, int l, int r, int x){
	if(l>x||Mx(x, tr[k])==x) return 0;
	if(l==r) return tr[k];int res=queryL(rs, mid+1, r, x);
	return res?res:queryL(ls, l, mid, x);
}
int queryR(int k, int l, int r, int x){
	if(r<x||Mx(x, tr[k])==x) return n+1;
	if(l==r) return tr[k]?tr[k]:n+1;int res=queryR(ls, l, mid, x);
	return (res<=n)?res:queryR(rs, mid+1, r, x);
}

G

只会在一个单调不降段开头买入结尾卖出,等价于 \(a_{i}>a_{i-1}\) 的有 \(a_{i}-a_{i-1}\) 的贡献,前缀和即可。

H

假设最短路是 \(d\), 设 \(d=kr+d'\)

如果 \(l<r\) 则在最后一步必然可以使用 与 \(d'\) 奇偶性相同的值在走到终点后反复横跳,\(ans=k+1\)

那么 \(l=r\) 的情况也同理分奇偶考虑,偶数情况是简单的,只能考虑长度为偶数的最短路。奇数情况,两种奇偶性最短路都要考虑,并且如果消耗时间*步数与奇偶性不同还要额外 +1 。

关键代码:

	if(L<R){
		p=min(dis[0][id(n, m)], dis[1][id(n, m)]);
		if(p!=INF) printf("%d\n", (p+R-1)/R);
		else puts("-1");
	} 
	else if(L%2){//奇数
		int u=dis[0][id(n, m)], v=dis[1][id(n, m)];
		if(u!=INF){u=(u+L-1)/L;if((u&1)==1) ++u;}
		if(v!=INF){v=(v+R-1)/R;if((v&1)==0) ++v;}
		if(min(u, v)==INF) puts("-1");
		else printf("%d\n", min(u, v));
	}
	else{
		p=dis[0][id(n, m)];
		if(p!=INF) printf("%d\n", (p+L-1)/L);
		else puts("-1");
	}

I

从特殊情况入手,全是割点无解,因为 \(n\) 至少需要两条出边连向同一个连通块,这连个出边的点就不嫩是割点。

一个非割点同理,构造链考虑,如果 \(n-1\) 是非割点则可以和 \(n\) 一起连到 \(n-2\),否则无解。

度数的 \(\ge\) 条件引导我们构造一连串的等于条件,容易想到 环 和 链中间 的点都满足度数为 \(2\),且环上是非割点而链是割点,于是让 1 作为环和链的交点,\(n\) 作为链的另一头。

J

lowbit 二进制构造。

K

先待定 \(b_1=0\),那么可以推算得 \(b_{i}=x_{i}+c_ib_{1}, c_{i}=1/-1\) ,根据深度以及 \(b_{i}\) 正负性简单分讨即可。

L

前缀子集 \(\min+\max\) 的众数

对于前缀 \([1, i]\),一共有 \(2^i-1\) 种情况,其中最大值+最小值保底有 \(2^{i-2}\) 种,容易发现只有 \(1, 2, 2,..., 2\) 时才会实现反超。

A

题面一坨,可读性不如代码。。。

考虑 DAG 剖,每个结点维护一个 ds 二元组集合统计 \((mx, cnt)\),转移时轻边直接暴力取出所有元素加入,重边则继承出点的 ds。ds 使用线段树,复杂度 \(O(n\log ^2 n)\)

参考代码
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define vi vector
#define pb push_back
#define mp make_pair
#define st first
#define nd second
using namespace std;
typedef long long ll;
typedef pair  Pii;
const int INF=0x3f3f3f3f;
const int cp=998244353;
inline int mod(int x){return x+(x<0?cp:0)-(x>=cp?cp:0);}
inline void plust(int &x, int y){x=mod(x+y);return ;}
inline void minut(int &x, int y){x=mod(x-y);return ;}
inline int read(){
	char ch=getchar();int x=0, f=1;
	while(!isdigit(ch)){if(ch=='-') f=-1; ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x){
    if(x<0) putchar('-'), x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
}
inline int ksm(int a, int b=cp-2){
	int ret=1;
	for(; b; b>>=1, a=1ll*a*a%cp)
		if(b&1) ret=1ll*ret*a%cp;
	return ret;
}
const int N=2e5+5;
char s[N];int n;
namespace SAM{
	const int Nc=N<<1;//SAM 实际点数卡满 2n-1
	const int Mc=(N<<1)+N;//SAM 实际边数卡满 3n-4
	int ndc, lst, siz[Nc], c[Nc], out[Nc], in[Nc], dfn[Nc], bac[Nc];
	ll f[Nc], g[Nc];vi dag[Nc], inv[Nc], G[Nc];
	struct node{int fa, len, nxt[26];}sam[Nc];
	int clear(int x){sam[x]=sam[0], siz[x]=0;return x;}
	void remake(){clear(ndc=lst=1), dfn[0]=0;}
	int insert(char c){
		int cur=clear(++ndc), p=lst, cc=c-'a';siz[cur]=1;
		sam[cur].len=sam[lst].len+1;
		for(; p&&!sam[p].nxt[cc]; p=sam[p].fa)
			sam[p].nxt[cc]=cur;
		int q=sam[p].nxt[cc];
		if(!q) sam[cur].fa=1;
		else if(sam[q].len==sam[p].len+1) sam[cur].fa=q;
		else{
			int nex=clear(++ndc);sam[nex]=sam[q], sam[nex].len=sam[p].len+1;
			for(; p&&sam[p].nxt[cc]==q; p=sam[p].fa) 
				sam[p].nxt[cc]=nex;
			sam[cur].fa=sam[q].fa=nex;
		}
		return lst=cur;
	}
	void dfs(int x){bac[dfn[x]=++dfn[0]]=x;for(auto v:dag[x]) if(!dfn[v]) dfs(v);}
	void dfs2(int x){for(auto v:G[x]) dfs2(v), siz[x]+=siz[v];}
	inline bool heavy(int u, int v){return (2ll*f[u]>f[v])&&(2ll*g[v]>g[u]);}
	#define ls(p) tr[p].lc
	#define rs(p) tr[p].rc
	#define C(p) tr[p].cnt
	#define S(p) tr[p].sum
	#define mid ((l+r)>>1)
	const int M=Nc*90;
	const int P=2e5;
	struct seg{int lc, rc;ll cnt, sum;};
	int m, rt[Nc];seg tr[M];
	vi bin;
	inline int newnd(){
		int t=0;if(!bin.size()) t=++m;
		else{ 
			t=bin.back(), bin.pop_back();
			if(ls(t)) bin.pb(ls(t));
			if(rs(t)) bin.pb(rs(t));
		}
		tr[t]=(seg){0, 0, 0, 0};return t;
	}
	void update(int &k, int l, int r, int u, ll c){
		if(!c) return ;
		if(!k) k=newnd();if(l==r){C(k)+=c, S(k)+=c*mid;return ;}
		if(u<=mid) update(ls(k), l, mid, u, c);else update(rs(k), mid+1, r, u, c);
		C(k)=C(ls(k))+C(rs(k)), S(k)=S(ls(k))+S(rs(k));
	}
	ll cover(int &k, int l, int r, int U){//查询且覆盖
		if(!k) return 0;if(l>=U) return 0;
		if(r Q;Q.push(f[1]=1);vi topo;
		while(!Q.empty()){
			int x=Q.front();Q.pop();topo.pb(x);
			for(auto v:dag[x]){
				f[v]+=f[x];--in[v];
				if(!in[v]) Q.push(v);
			}
		}
		for(int i=ndc; i>=1; --i) 
			if(!out[i]) Q.push(i), g[i]=1;
		while(!Q.empty()){
			int x=Q.front();Q.pop();
			for(auto v:inv[x]){
				g[v]+=g[x];--out[v];
				if(!out[v]) Q.push(v);
			}
		}
		// for(int i=1; i<=ndc; ++i) printf("%d ", siz[i]);puts("");
		ll ans=0;update(rt[1], 1, P, c[1], 1);
		for(auto x:topo){
			int son=0;ll p=cover(rt[x], 1, P, c[x]);update(rt[x], 1, P, c[x], p);
			ans+=tr[rt[x]].sum*siz[x];
			for(auto v:dag[x]) 
				if(!heavy(x, v)) copy(rt[v], rt[x], 1, P);else son=v;
			if(son) swap(rt[son], rt[x]), copy(rt[son], rt[x], 1, P);
		}
		printf("%lld\n", ans);bin.clear();
		for(int i=1; i<=ndc; ++i) 
			dag[i].clear(), inv[i].clear(), G[i].clear(),
			f[i]=g[i]=in[i]=dfn[i]=bac[i]=out[i]=rt[i]=siz[i]=c[i]=0;
	}
}
void solve(){
	scanf("%s", s+1);n=strlen(s+1);SAM :: init();
}
signed main(){
	for(int T=read(); T; --T) solve();
	return 0;
}
posted @ 2025-07-05 12:57  127_127_127  阅读(132)  评论(0)    收藏  举报