千疮百孔的心被恨与悲彻底剥离 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

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;
}

浙公网安备 33010602011771号