齿轮运行思考的海马体 渐渐懂得黑与白不同意义 这就是我缺少的吗

test19

深度优先搜索dfs

先不考虑顺序,一次操作相当于 \((x,x+1)\to x\),那么显然是从大到小一直一直做到不行,要求只有 \(1\)\(0\) 且对于 \(a_i\) 存在 \(a_i-1\)

那么我们在有序数列上考虑类似的过程,拿取一个最大的 \(a\) 删掉(有多个优先拿最边缘的,不难发现不相互影响),相当于要求其左右第一个更小的数至少有一个是 \(a_{i-1}\)

#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)

using namespace std;

const int N=100005;

int T, n, a[N], L[N], R[N], stk[N], top;

void mian() {
	cin >> n;
	up(i,1,n) cin >> a[i];
	stk[top=0]=-1;
	up(i,1,n) {
		while(top&&stk[top]>=a[i]) --top;
		L[i]=stk[top], stk[++top]=a[i];
	}
	stk[top=0]=-1;
	dn(i,n,1) {
		while(top&&stk[top]>=a[i]) --top;
		R[i]=stk[top], stk[++top]=a[i];
	}
	int cnt=0;
	up(i,1,n) {
		if(a[i]==0) ++cnt;
		if(a[i]&&(L[i]==-1||L[i]+1!=a[i])&&(R[i]==-1||R[i]+1!=a[i])) {
			cout << "NO\n";
			return;
		}
	}
	if(cnt==1) cout << "YES\n";
	else cout << "NO\n";
}

signed main() {
	freopen("dfs.in","r",stdin);
	freopen("dfs.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

弹珠pinball

好像为数不多打的几次 cf 里面就包含了这道题 /fad

手动模拟这个过程画图看看,设 \(pre_i/suf_i\) 表示前/缀的 \(\text{>,<}\) 个数,最终走哪边是可以用 \(str_i,pre_{i-1},suf_{i+1}\) 确定的贡献一个 \(i/n-i+1\),别的贡献拆成很多个走到一个逆向点再走回起点的过程,计算左右最后 \(\min(pre_{i-1},suf_{i+1})(+1)\)\(\text{>,<}\) 的位置和即可,懒得说的很详细惹。

#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)

using namespace std;

const int N=200005;

int T, n, pre[N], suf[N], L[N], R[N], Ans[N], tot, sum[N];
char str[N];

void mian() {
	cin >> n >> (str+1), suf[n+1]=0;
	up(i,1,n) pre[i]=pre[i-1]+(str[i]=='>');
	dn(i,n,1) suf[i]=suf[i+1]+(str[i]=='<');
	up(i,1,n) {
		L[i]=R[i]=min(pre[i-1],suf[i+1]);
		if(pre[i-1]>suf[i+1]&&str[i]=='<') ++L[i];
		if(pre[i-1]<suf[i+1]&&str[i]=='>') ++R[i];
		if(pre[i-1]<suf[i+1]||pre[i-1]==suf[i+1]&&str[i]=='<') Ans[i]=i;
		if(pre[i-1]>suf[i+1]||pre[i-1]==suf[i+1]&&str[i]=='>') Ans[i]=n-i+1;
	}
	sum[tot=0]=0;
	up(i,1,n) {
		Ans[i]+=2*(L[i]*i-sum[tot]+sum[tot-L[i]]);
		if(str[i]=='>') ++tot, sum[tot]=sum[tot-1]+i;
	}
	sum[tot=0]=0;
	dn(i,n,1) {
		Ans[i]+=2*(sum[tot]-sum[tot-R[i]]-R[i]*i);
		if(str[i]=='<') ++tot, sum[tot]=sum[tot-1]+i;
	}
	up(i,1,n) cout << Ans[i] << ' '; cout << '\n';
}

signed main() {
	freopen("pinball.in","r",stdin);
	freopen("pinball.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}

字符串string

\(fc_{i}=1/-1/0[a_i<a_{i-1}/a_i>a_{i-1}/a_i=a_{i-1}]\),那么原题目的限制 \(a<b\) 就是要求 \(fc_{a+1,\dots,b}=00001\)\(a=b\) 不用管,\(a>b\) 就是要求 \(fc_{b+1,\dots,a}=0000-1\)。意思就是对于选择有两维度限制,能不能选更大/更小的数,而满足条件的前提下变化一个值会清空限制。

带着 \(fc_i=0\) 和限制不太好 dp,不妨考虑 \(f_{i,j}\) 表示最后一个 \(fc\neq 0\) 的是 \(i\) 的答案,转移 \(i\) 的时候对于 \(j<i\) 只关心存不存在跨越的每种限制,每一类型的 \(j\) 显然是一个区间,前缀和优化即可。

#define _CRT_SECURE_NO_WARNINGS
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")


#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=100005, P=1e9+7, lim=26;

int id, T, n, m, Ans, f[N][27], L[N], R[N], p[N][28], q[N][28];
vector<int> add1[N], del1[N], add2[N], del2[N];

inline void add(int &a,int b) { a=(a+b)%P; }

void mian() {
	memset(f,0,sizeof(f));
	memset(p,0,sizeof(p));
	memset(q,0,sizeof(q));
	cin >> n >> m, Ans=0;
	while(m--) {
		int a, b;
		cin >> a >> b;
		if(a<b) add1[a+1].pb(a+1), del1[b].pb(a+1);
		if(a>b) add2[b+1].pb(b+1), del2[a].pb(b+1);
	}
	multiset<int> qwq;
	up(i,1,n) {
		for(int v:add1[i]) qwq.insert(v);
		if(qwq.size()) L[i]=*--qwq.end()-1; else L[i]=0;
		for(int v:del1[i]) qwq.erase(qwq.find(v));
		add1[i].clear(), del1[i].clear();
	} qwq.clear();
	up(i,1,n) {
		for(int v:add2[i]) qwq.insert(v);
		if(qwq.size()) R[i]=*--qwq.end()-1; else R[i]=0;
		for(int v:del2[i]) qwq.erase(qwq.find(v));
		add2[i].clear(), del2[i].clear();
	}
	up(i,1,lim) f[1][i]=1;
	up(i,1,lim) p[1][i]=(p[1][i-1]+f[1][i])%P;
	dn(i,lim,1) q[1][i]=(q[1][i+1]+f[1][i])%P;
	up(i,2,n) {
		up(j,1,lim) add(f[i][j],f[i-1][j]);
		if(L[i]&&R[i]) {
			int l=min(L[i],R[i]), r=max(L[i],R[i]);
			up(j,1,lim) {
				if(r+1<i) {
					add(f[i][j],(p[i-1][j-1]-p[r][j-1])%P);
					add(f[i][j],(q[i-1][j+1]-q[r][j+1])%P);
				}
				if(L[i]>R[i]) {
					if(l<r) add(f[i][j],(q[r][j+1]-q[l][j+1])%P);
				}
				else {
//					if(l<r) add(f[i][j],(p[r][j-1]-p[l][j-1])%P);
					if(l<r) //add(f[i][j],q[r][j+1]-q[l][j+1]);
					up(v,1,j-1) {
						add(f[i][j],(f[r][v]-f[l][v])%P);
					}
				}
			}
		}
		else if(L[i]) {
			up(j,1,lim) {
				if(L[i]+1<i) {
					add(f[i][j],(p[i-1][j-1]-p[L[i]][j-1])%P);
					add(f[i][j],(q[i-1][j+1]-q[L[i]][j+1])%P);
				}
				add(f[i][j],q[L[i]][j+1]);
			}
		}
		else if(R[i]) {
			up(j,1,lim) {
				if(R[i]+1<i) {
					add(f[i][j],(p[i-1][j-1]-p[R[i]][j-1])%P);
					add(f[i][j],(q[i-1][j+1]-q[R[i]][j+1])%P);
				}
				add(f[i][j],p[R[i]][j-1]);
			}
		}
		else {
			up(j,1,lim) {
				add(f[i][j],p[i-1][j-1]);
				add(f[i][j],q[i-1][j+1]);
			}
		}
		up(j,1,lim) p[i][j]=(p[i][j-1]+f[i][j])%P;
		dn(j,lim,1) q[i][j]=(q[i][j+1]+f[i][j])%P;
	}
	up(i,1,lim) add(Ans,f[n][i]);
	cout << (Ans%P+P)%P << '\n';
}

signed main() {
	freopen("string.in","r",stdin);
	freopen("string.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> id >> T;
	while(T--) mian();
	return 0;
}

酒厂wine

直接做好像不太好做,但是发现以初始输入水流为横坐标维护答案(输出水量、酿酒量)曲线是容易的,因为答案曲线形态很简单。对于酿酒量,最开始应该是加一点水就多一点酒,最后应该是怎么加水都不加酒,而对于输入水量,应该是最开始不变(因为拿去酿酒了),然后多一点输入水就多输出一点水,最后怎么加水都不会多输出,发现需要维护初始酿酒量 \(ans\),可额外酿酒量 \(lim\),初始出水量 \(res\),开始停出水量 \(top\),线段树做修改及即可,合并和初始化用以下等式:

\(ans=ans_l+酒_r(res_l),res=水_r(res_l),res+top-lim=水_r(res_l+top_l-lim_l),ans+lim=酒_r(res_l+top_l-lim_l)+酒_l(\infty)\)

\(ans=min(a,b),lim=b-min(a,b),res=min(c,a-ans),top=lim+c-res\)

#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
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)

using namespace std;

const int N=200005;

int id, n, q, a[N], b[N], c[N];
struct node {
	int ans, lim, res, top;
	node() { ans=lim=res=top=0; }
	node(int a,int b,int c) {
		ans=min(a,b);
		lim=b-ans;
		res=min(c,a-ans);
		top=lim+c-res;
	}
	int jiu(int x) {
		if(x<=lim) return ans+x;
		return ans+lim;
	}
	int shui(int x) {
		if(x<=lim) return res;
		if(lim<x&&x<=top) return res+x-lim;
		return res+top-lim;
	}
} tr[N<<2];

node merge(node l,node r) {
	node ret;
	ret.ans=l.ans+r.jiu(l.res);
	ret.res=r.shui(l.res);
	ret.lim=l.jiu(1e18)+r.jiu(l.res+l.top-l.lim)-ret.ans;
	ret.top=r.shui(l.res+l.top-l.lim)+ret.lim-ret.res;
	return ret;
}

void build(int p=1,int s=1,int e=n) {
	if(s==e) {
		tr[p]=node(a[s],b[s],c[s]);
//	cout << "check " << s << ' ' << e << " : " << tr[p].ans << ' ' << tr[p].lim << ' ' 
//		<< tr[p].res << ' ' << tr[p].top << '\n';
		return;
	}
	int mid=(s+e)>>1;
	build(ls(p),s,mid), build(rs(p),mid+1,e);
	tr[p]=merge(tr[ls(p)],tr[rs(p)]);
//	cout << "check " << s << ' ' << e << " : " << tr[p].ans << ' ' << tr[p].lim << ' ' 
//		<< tr[p].res << ' ' << tr[p].top << '\n';
}

void updata(int x,int p=1,int s=1,int e=n) {
	if(s==e) {
		tr[p]=node(a[s],b[s],c[s]);
		return;
	}
	int mid=(s+e)>>1;
	if(x<=mid) updata(x,ls(p),s,mid);
	if(x>mid) updata(x,rs(p),mid+1,e);
	tr[p]=merge(tr[ls(p)],tr[rs(p)]);
} 

signed main() {
	freopen("wine.in","r",stdin);
	freopen("wine.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> id >> n >> q;
	up(i,1,n) cin >> a[i];
	up(i,1,n) cin >> b[i];
	up(i,1,n) cin >> c[i];
	c[n]=0, build();
//	cout << tr[1].ans << '\n';
	while(q--) {
		int x; cin >> x;
		cin >> a[x] >> b[x] >> c[x];
		updata(x), cout << tr[1].ans << '\n';
	}
	return 0;
}
posted @ 2025-10-14 19:14  Hypoxia571  阅读(6)  评论(0)    收藏  举报