我不懂 愈完美愈是空洞 挂着张可憎面容 维系虚假脆弱的梦

test8


割串aa

为什么没有大样例只有本可过不了 /fad

首先 \(\text{a}\) 是特殊的,扣掉 \(\text{a}\) 考虑,会形成字符串 \(p_1,\dots,p_m\),顺着来就是要考虑 \(t_i\neq \text{a}\) 的情况。那么显然 \(t\) 的充要条件是 \(t|p_i\)\(p_i\) 由若干 \(t\) 构成),不妨枚举 \(t=p_1[1,1],p_1[1,2],\dots,p_1[1,|p_1|]\),哈希暴力验证复杂度 \(O(n\log n)\)

现在考虑怎么做 \(\exists t_i=\text{a}\) 的情况惹,考虑一个 \(t\) 涵盖 \(u\)\(p\)。若 \(u=m\),前/后缀 \(pre/nxt\)\(a\) 贡献 \((pre+1)(nxt+1)-[m=1]\),之后只用考虑 \(u<m\) 的情况惹。首先 \(ku+[1,u]\) 肯定放在一块的,要求中间的间隔 \(a\) 形式相同,然后考虑最前缀/后缀和大段间隔最小 \(\text{a}\) 数量,设在前/后拼凑 \(l/r\) 个,就是要求 \((l,r)\) 数量满足 \(0\leq l\leq pre,0\leq r\leq nxt,l+r\leq \min\)仔细分类讨论可以等差数列求出和。

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back

using namespace std;

const int N=300005, inf=1e13;
const ull B=233;

int T, n, m, ans, L[N], R[N];
ull pw[N], hsh[N];
char str[N];

inline ull get(int l,int r) {
	return hsh[r]-hsh[l-1]*pw[r-l+1];
}

void mian() {
	cin >> (str+1), n=strlen(str+1), m=ans=0;
	up(i,1,n) hsh[i]=hsh[i-1]*B+(str[i]-'a'+1);
	for(int l=1, r=1; l<=n; l=r+1, r=l) {
		if(str[l]=='a') continue;
		while(r<n&&str[r+1]!='a') ++r;
		++m, L[m]=l, R[m]=r;
	}
	if(!m) { cout << n-1 << '\n'; return; }
	up(len,1,R[1]-L[1]+1) {
		bool flag=1;
		up(i,1,m) {
			if(!flag||(R[i]-L[i]+1)%len!=0) { flag=0; break; }
			for(int j=L[i]; j<=R[i]; j+=len) {
				if(get(j,j+len-1)!=get(L[1],L[1]+len-1)) flag=0;
			}
		}
		ans+=flag;
	}
	int pre=0, nxt=0;
	up(i,1,n) if(str[i]!='a') break; else ++pre;
	dn(i,n,1) if(str[i]!='a') break; else ++nxt;
	int flag=1;
	up(i,2,m) {
		if(R[i]-L[i]!=R[i-1]-L[i-1]) flag=0;
		up(j,1,R[i]-L[i]+1) if(str[L[i-1]+j-1]!=str[L[i]+j-1]) flag=0;
	}
//	cout << "side " << ans << '\n';
	up(u,1,m) {
		if(m%u!=0||m!=u&&!flag) continue; 
		int flag=1, fc=R[u]-L[1]+1, p=inf;
		for(int l=1; l<=m; l+=u) {
			int r=l+u-1;
			if(R[r]-L[l]+1!=fc) { flag=0; break; }
			if(l>1) p=min(p,L[l]-R[l-1]-1);
		}
		if(!flag) continue;
//		cout << "qwq " << pre << ' ' << p << ' ' << nxt << '\n';
		if(p==inf) ans+=(pre+1)*(nxt+1);
		else {
			int l=p, r=max(p-pre,0ll);
//			cout << "? " << nxt << ' ' << l << ' ' << r << '\n';
			ans+=l-r+1;
			if(r<=nxt&&nxt<=l) {
				ans+=nxt*(l-nxt);
				ans+=(r+nxt)*(nxt-r+1)/2;
			}
			else {
				if(nxt>l) ans+=(l+r)*(l-r+1)/2;
				if(nxt<l) ans+=(l-r+1)*nxt;
			}
		}
		if(u==1) --ans;
//		cout << "len = " << u << " : " << ans << '\n';
	}
	cout << ans << '\n';
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("aa.in","r",stdin);
	freopen("aa.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	pw[0]=1;
	up(i,1,3e5) pw[i]=pw[i-1]*B;
	cin >> T;
	while(T--) mian();
	return 0;
}

宝石gem

先拓扑排序出任意合法填数方式,之后都用新编号表示。考虑 \(i\) 合法的条件显然是 \(\forall j<i,\exists to_j\leq i\)\(\forall j>i,\exists pre_j\geq i\)。不妨对 \(j\) 考虑使得哪些 \(i\) 不合法,把限制时间打到点上就做完了。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i) 
#define pii pair<int,int>
#define mp make_pair
#define pb push_back

using namespace std;

const int N=800005;

int n, m, ret[N], tot, ans[N], u[N], v[N], in[N];
vector<pii> F[N], G[N];
vector<int> add[N], del[N], to[N];
multiset<int> qwq;
queue<int> q;

signed main() {
	freopen("gem.in","r",stdin);
	freopen("gem.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> m;
	up(i,1,m) {
		cin >> u[i] >> v[i];
		to[u[i]].pb(v[i]), ++in[v[i]];
	}
	up(i,1,n) if(!in[i]) q.push(i);
	while(q.size()) {
		int x=q.front(); q.pop();
		ret[x]=++tot;
		for(int y:to[x]) if(!--in[y]) q.push(y);
	}
	up(i,1,m) {
		F[ret[u[i]]].pb(mp(ret[v[i]],i));
		G[ret[v[i]]].pb(mp(ret[u[i]],i));
	}
	qwq.insert(0);
	up(i,1,n) {
		int lst=n+1;
		for(pii p:F[i]) {
			int j=p.first, t=p.second;
			if(j>=lst) continue;
			add[j].pb(t), del[lst-1].pb(t), lst=j;
		}
		if(i+1<lst) add[i+1].pb(m+1), del[lst-1].pb(m+1);
	}
	up(i,1,n) {
		for(int x:add[i]) qwq.insert(x);
		ans[i]=*--qwq.end();
		for(int x:del[i]) qwq.erase(qwq.find(x));
	}
	qwq.clear(), qwq.insert(0);
	up(i,0,n+1) add[i].clear(), del[i].clear();
	up(i,1,n) {
		int lst=0;
		for(pii p:G[i]) {
			int j=p.first, t=p.second;
			if(j<=lst) continue;
			add[lst+1].pb(t), del[j].pb(t), lst=j;
		}
		if(lst+1<i) add[lst+1].pb(m+1), del[i-1].pb(m+1);
	}
	up(i,1,n) {
		for(int x:add[i]) qwq.insert(x);
		ans[i]=max(ans[i],*--qwq.end());
		for(int x:del[i]) qwq.erase(qwq.find(x));
	}
	up(j,1,n) {
		int i=ret[j];
		cout << (ans[i]<=m?ans[i]:-1) << ' ';
	}
	return 0;
}

石头人stone

有奶龙龙龙喵因为 \(i/-i\) 写反了调了半天 /yun

设加入的顺序为 \(v_1,\dots,v_n\),那么答案显然是 \(-v_1+\sum_{i=1}^n(n+1-i)\times v_i\),也就是 \(\sum_{i=1}^n v_i\times i \downarrow\)

首先考虑左/右边可以拓展一个长度为 \(l/r\) 的段 \(\{L\},\{R\}\)(下标按加入顺序),容易发现它们的相对顺序没有后效性,且 \(L\)\(R\) 先当且仅当 \(\sum L_i\times r\geq \sum R_i \times l\) 也就是平均数小的放在前面。那么我们很自然地猜测每一次拓展向平均数最小的新段,这个容易反证法验证到,假设 \(ave_{\min}\) 在一边,另一边先拿根据刚刚的贪心肯定不优。

容易想到离线,对于所有的跳跃按照平均数递增排序,这样子数组左边的肯定先拿,用线段树维护前后缀的 \(\sum len_i\) 以及 \(\sum v_i\) 即可。

问题只剩求解对于 \(i\) 其向前/后的最小平均数在哪里,以及这个东西的数量级能不能支撑上面的做法,以前缀为例。设前缀和为 \(s\),就想要找到 \(\frac{S_i-S_j}{i-j}\) 最大的 \(j\) 作为下一个端点,这个显然斜率优化可以解决,顺着维护一个凹包即可,然后加入删除是 \(O(n)\) 的,打到点上计算贡献即可。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i) 
#define pb push_back 

using namespace std;

const int N=800005;

int n, m, a[N], S[N], SS[N], ans, q[N], qwq[N], L, R, ret[N], tr1[N], tr2[N], jury;
vector<int> add[N], del[N];
struct node {
	int id, now, nxt, len, s, ss;
	node() {}
	node(int Id,int Now,int Nxt) {
		id=Id, now=Now, nxt=Nxt;
		len=abs(now-nxt), s=S[now]-S[nxt];
		if(nxt<now) ss=SS[now]-SS[nxt]-(n-now)*s;
		else ss=SS[now]-SS[nxt]-(now-1)*s;
	}
	bool operator<(const node &rhs) const {
		return s*rhs.len<rhs.s*len;
	}
} p[N];

double ave1(int l,int r) { return (double)(S[r]-S[l])/(r-l); }
double ave2(int l,int r) { return (double)(S[l]-S[r])/(r-l); }

void add1(int x,int v) { for( ; x<=m; x+=x&-x) tr1[x]+=v; }
void add2(int x,int v) { for( ; x<=m; x+=x&-x) tr2[x]+=v; }
int ask1(int x) { int ret=0; for( ; x; x-=x&-x) ret+=tr1[x]; return ret; }
int ask2(int x) { int ret=0; for( ; x; x-=x&-x) ret+=tr2[x]; return ret; }

void UP(int u) {
	u=ret[u], ans+=p[u].ss;
	ans+=ask1(u)*p[u].s, add1(u,p[u].len);
	ans+=(ask2(m)-ask2(u))*p[u].len, add2(u,p[u].s);
}

void DN(int u) {
	u=ret[u], ans-=p[u].ss;
	add1(u,-p[u].len), ans-=ask1(u)*p[u].s;
	add2(u,-p[u].s), ans-=(ask2(m)-ask2(u))*p[u].len;
}

signed main() {
	freopen("stone.in","r",stdin);
	freopen("stone.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	up(i,1,n) cin >> a[i], jury+=a[i]*(n); 
	q[L=R=1]=0;
	up(i,1,n) {
		S[i]=S[i-1]+a[i], SS[i]=SS[i-1]+a[i]*(n-i+1); 
		while(L<R&&ave1(q[R-1],q[R])<=ave1(q[R-1],i)) del[i+1].pb(qwq[R--]);
		q[++R]=i, add[i+2].pb(qwq[R]=++m), p[m]=node(m,i,q[R-1]);
	} 
	q[L=R=1]=n+1;
	dn(i,n,1) {
		S[i]=S[i+1]+a[i], SS[i]=SS[i+1]+a[i]*i;
		while(L<R&&ave2(q[R-1],q[R])<=ave2(q[R-1],i)) add[i+1].pb(qwq[R--]);
		q[++R]=i, del[i].pb(qwq[R]=++m), p[m]=node(m,i,q[R-1]);
	}
	sort(p+1,p+1+m);
	up(i,1,m) ret[p[i].id]=i;
	while(L<R) UP(qwq[R--]);
	up(i,1,n+1) {
		for(int u:add[i]) UP(u);
		if(i>1) cout << jury-ans-a[i-1] << ' ';
		for(int u:del[i]) DN(u);
	}
	return 0;
}

染色col

招笑嘛,这个题是 r5 的 t2。

#include<bits/stdc++.h>
#define int long long
#define up(i,l,r) for(int i=l; i<=r; ++i)
#define dn(i,r,l) for(int i=r; i>=l; --i)
#define pb push_back

using namespace std;

const int N=200005;

int T, n, a, b, Ans, dep[N], len, fa[N];
vector<int> to[N]; 

void dfs(int x) {
	for(int y:to[x]) if(!dep[y]) {
		dep[y]=dep[x]+1;
		fa[y]=x, dfs(y);
		len=max(len,dep[y]);
	}
}

void sol(int S) {
	up(i,1,n) dep[i]=0;
	len=1, dep[S]=1, dfs(S);
}

int upper(int x,int d) {
	if(dep[x]==d) return x;
	return upper(fa[x],d);
}

void mian() {
	Ans=0;
	cin >> n >> a >> b;
	up(i,1,n) to[i].clear();
	up(i,2,n) {
		int u, v;
		cin >> u >> v;
		to[u].pb(v);
		to[v].pb(u);
	}
	sol(a);
	if(a==b) {
		cout << 2*(n-1)-len+1 << '\n';
		return; 
	}
	if(dep[b]&1) {
		Ans+=(dep[b]-1)/2;
		int c=upper(b,(1+dep[b])/2);
		sol(c), Ans+=2*(n-1)-len+1;
	}
	else {
		Ans+=dep[b]/2;
		int c=upper(b,dep[b]/2);
		sol(c), Ans+=2*(n-1)-len+1;
	}
	cout << Ans << '\n';
}

signed main() {
	freopen("col.in","r",stdin);
	freopen("col.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}
posted @ 2025-09-28 22:05  Hypoxia571  阅读(16)  评论(0)    收藏  举报