千疮百孔的心被恨与悲彻底剥离 Kill my memory 让我将快乐全忘记

test26

我当逐明月枕清风qingfeng

区间加减先改成在差分数组上选择 \(i,j\in [1,n+1],i\neq j\) 使得 \(d_i\gets d_{i}+1,d_j\gets d_{j}-1\),目标就是让 \(d_{2\to n}=0\),所以考虑让函数 \(f(d)=\sum_{i=2}^n |d_i|\) 下降到 \(0\)。首先如果 \(i,j\in [2,n]\)\(d_id_j<0\),会使 \(f\) 下降 2,这是最优的,在存在这样的合法对时一定会用这种。然后就是 \(\forall d_{2\to n}\geq 0\) 或者反之的情况了,可以选择向 \(d_1/d_{n+1}\) 传递贡献,让 \(f\) 下降 \(1\),设 \(L=\sum_{i=2}^n[d_i>0]d_i,R=\sum_{i=2}^n [d_i<0]|d_i|\),那么操作次数一定是 \(max(L,R)\),还没有严谨阐述的正确性都可以对着 \(f\) 捏出来,注意到让 \(f\)\(1\) 的贡献可以选择放左/右 \(x,|L-R|-x\) 次这种对,所以序列数就是 \(|L-R|+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 n, a[N], L, R;

signed main() {
	freopen("qingfeng.in","r",stdin);
	freopen("qingfeng.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n;
	up(i,1,n) cin >> a[i];
	dn(i,n,1) a[i]-=a[i-1];
	up(i,2,n) if(a[i]<0) L-=a[i]; else R+=a[i];
	cout << max(L,R) << '\n' << abs(L-R)+1 << '\n';
	return 0;
}

一身坦荡明晃晃魑魍魉wangliang

首先这个是有向图,其次这个不是 dag,所以最长路不行,那我们只能考虑建图缩点然后 dfs,建图的话对需要的行或者列建立一个辅助点即可。

#include<bits/stdc++.h>
#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=300005;
const int dx[9]={0,1,-1,0,0,1,1,-1,-1};
const int dy[9]={0,0,0,1,-1,1,-1,1,-1};

int n, m, R, C, x[N], y[N], opt[N];
int stk[N], top, gp[N], vis[N], cnt, p, val[N], Ans;
vector<int> F[N], G[N], to[N];
map<int,int> idx, idy;
map<pii,int> qwq;

inline void eadd(int u,int v) {
	F[u].pb(v), G[v].pb(u);
}

void dfs(int x) {
	vis[x]=1;
	for(int y:F[x]) if(!vis[y]) dfs(y);
	stk[++top]=x;
}

void stain(int x) {
	for(int y:G[x]) if(!gp[y]) gp[y]=cnt, stain(y);
}

void Dfs(int x) {
	vis[x]=val[x];
	for(int y:to[x]) {
		if(!vis[y]) Dfs(y);
		vis[x]=max(vis[x],vis[y]+val[x]);
	}
	Ans=max(Ans,vis[x]);
}

signed main() {
	freopen("wangliang.in","r",stdin);
	freopen("wangliang.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> n >> R >> C, m=n;
	up(i,1,n) {
		cin >> x[i] >> y[i] >> opt[i];
		if(opt[i]==1&&!idx[x[i]]) idx[x[i]]=++m;
		if(opt[i]==2&&!idy[y[i]]) idy[y[i]]=++m; 
		qwq[mp(x[i],y[i])]=i;
	}
	up(i,1,n) {
		if(idx.find(x[i])!=idx.end()) eadd(idx[x[i]],i);
		if(idy.find(y[i])!=idy.end()) eadd(idy[y[i]],i);
		if(opt[i]==1) eadd(i,idx[x[i]]);
		if(opt[i]==2) eadd(i,idy[y[i]]);
		if(opt[i]==3) {
			up(o,1,8) {
				int xx=x[i]+dx[o], yy=y[i]+dy[o];
				if(qwq.find(mp(xx,yy))!=qwq.end()) {
					int j=qwq[mp(xx,yy)];
					eadd(i,j);
				}
			} 
		}
	}
	up(i,1,m) if(!vis[i]) dfs(i);
	dn(i,m,1) if(!gp[p=stk[i]]) gp[p]=++cnt, stain(p);
	up(i,1,n) ++val[gp[i]]; 
	up(i,1,m) for(int j:F[i]) if(gp[i]!=gp[j]) to[gp[i]].pb(gp[j]);
	up(i,1,m) vis[i]=0;
	up(i,1,n) if(!vis[gp[i]]) Dfs(gp[i]);
	cout << Ans << '\n';
	return 0;
}

我当工有所偿学有所用suoyong

题目要求“自觉强制在线”,注意到分块也可以强制在线,那么写分块,但是不自觉地提前计算了 \(n=\sum |s_i|\) 来计算 \(B\) ,然后懒得取 \(\max\{len_i\}\) 用其预处理了哈希,然后就 RE 了,这是什么新型检验自觉性的方式嘛(?

其实我已经不太记得 ac 自动机怎么写了,但是这个一看就能根号分治不是吗。 \(len>B\) 的加入对 \(len\leq B\) 的查询没有贡献,\(len\leq B\) 的加入可以塞进哈希表、查询的时候考虑所有的左右端点的情况在哈希里面查数量,\(len>B\) 的插入对 \(len>B\) 的查询可以暴力做。

#include<bits/stdc++.h>
#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=3000005;
const ull base=233;

int n, m, B, opt[N], len[N], g[N];
string str[N]; ull pw[N]; 
vector<int> diff; 
vector<ull> hsh[N];
unordered_map<ull,int> counter;

int sub(int b,int a) { // 在 str[b] 里面找 str[a] 
	int m=len[b], n=len[a], ret=0, j=0;
	up(i,2,n) {
		while(j&&str[a][j+1]!=str[a][i]) j=g[j];
		j+=(str[a][j+1]==str[a][i]), g[i]=j;
	}
	j=0;
	up(i,1,m) {
		while(j&&(str[a][j+1]!=str[b][i]||j==n)) j=g[j];
		j+=(str[a][j+1]==str[b][i]);
		if(j==n) ++ret;
	}
	return ret;
}

signed main() {
	freopen("suoyong.in","r",stdin);
	freopen("suoyong.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> m;
	up(i,1,m) {
		cin >> opt[i] >> str[i];
		n+=(len[i]=str[i].size());
		str[i]=" "+str[i]+" ";
		hsh[i].resize(len[i]+1);
		up(j,1,len[i]) hsh[i][j]=hsh[i][j-1]*base+(str[i][j]-'a'+1);
	}
	B=sqrt(n), pw[0]=1;
	up(i,1,n) pw[i]=pw[i-1]*base; 
	up(i,1,m) {
		if(opt[i]==3) {
			int Ans=0;
			up(j,1,len[i]) up(k,1,min(j,B)) {
				ull val=hsh[i][j]-hsh[i][j-k]*pw[k];
				if(counter.find(val)!=counter.end()) Ans+=counter[val];
			}
			if(len[i]>B) for(int j:diff) Ans+=sub(i,j);
			cout << Ans << '\n';
		}
		else {
			int val=opt[i]==1?1:-1;
			if(len[i]<=B) counter[hsh[i][len[i]]]+=val;
			else diff.pb(i);
		}
	}
	return 0;
}

无人笑我不自量ziliang

image

dp 算的东西是折线,关心的有 现在时间/现在高度/历史最大高度,直接记这么多状态不太实际喵,考虑怎么优化掉历史最大高度,不妨把折线向上平移到切着 \(y=n\),截距 \(i\) 就是最大值是 \(n-i\) 的意思,好像有点能归到一起处理的意思了。要算期望我们希望令 \(f_{0,n-i}=h_i\),然后带着概率往下暴力 dp,顺手加一维 \(0/1\) 表示有没有碰到 \(y=n\),不妨认为 \(x/y-x\) 种方案往上走/往下走,计算总贡献即可,注意到一种形态的折线在同一时刻只有一条会触碰过顶端,这个的正确性可以保证。

计算的对象是 \((i,s_i)\) 的走势也就是图中的 \(l\),我们关心 \(l\) 的横向长度 \(i\),当前纵向高度 \(s_i\),以及纵向历史最大高度 \(h\),这个是三维的状态我们想办法优化掉一维。不妨将 \(l\) 平移到 \(l'\) 使得最高点在 \(y=n\) 上,这样子好像不关心 \(h\) 的具体值了只关心有没有碰到过越过 \(y=n\)

\(f_{i,j,0/1}\) 表示序列长度为 \(i\)\(y(i)=j\),没有/有碰到过 \(y=n\) 的期望,初始 \(f_{0,n-i,[i=0]}=h_i\),转移 \(f_{i-1,j,0/1}\times (\frac{x}{y}/\frac{y-x}{y})\to f_{i,j\pm 1,0/1}\),最后同层 \(f_{i,n,0}\to f_{i,n,1}\),一层的答案就是 \(\sum f_{i,j,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=5005, P=1e9+7;

int ksm(int a,int b=P-2) {
	int ret=1;
	for( ; b; b>>=1) {
		if(b&1) ret=ret*a%P;
		a=a*a%P;
	}
	return ret;
}

int T, n, p[N], q[N], h[N], f[2][N<<1][2];

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

void mian() {
	cin >> n;
	up(i,1,n) {
		int x, y;
		cin >> x >> y;
		p[i]=x, q[i]=y-x;
	}
	up(i,0,n) cin >> h[i];
	up(i,-n,n) f[0][i+n][0]=f[0][i+n][1]=0;
	up(i,0,n) f[0][n-i+n][i==0]=h[i];
	int mul=1;
	up(i,1,n) {
		int now=i&1, pre=now^1;
		up(j,-n,n) f[now][j+n][0]=f[now][j+n][1]=0;
		up(j,-n,n) {
			if(j<+n) {
				add(f[now][j+1+n][0],f[pre][j+n][0]*p[i]%P);
				add(f[now][j+1+n][1],f[pre][j+n][1]*p[i]%P);
			}
			if(j>-n) {
				add(f[now][j-1+n][0],f[pre][j+n][0]*q[i]%P);
				add(f[now][j-1+n][1],f[pre][j+n][1]*q[i]%P);
			}
		}
		add(f[now][n+n][1],f[now][n+n][0]), f[now][n+n][0]=0;
		int Ans=0;
		up(j,-n,n) add(Ans,f[now][j+n][1]);
		(mul*=ksm(p[i]+q[i]))%=P; 
		cout << (Ans%P+P)%P*mul%P << ' ';
	}
	cout << '\n';
}

signed main() {
//	freopen("1.txt","r",stdin);
	freopen("ziliang.in","r",stdin);
	freopen("ziliang.out","w",stdout);
	ios::sync_with_stdio(0);
	cin.tie(0);
	cin >> T;
	while(T--) mian();
	return 0;
}
posted @ 2025-10-22 16:17  Hypoxia571  阅读(7)  评论(0)    收藏  举报