P4692 [Ynoi2016] 谁的梦 题解
题目描述
定义一个序列的权值为不同数字的个数。
给定 \(n\) 个序列,从每个序列中选择一个子串并拼接起来,求所有选法得到的序列权值之和。
如果一个序列能通过多种选法得到,那么计算多次。
接下来 \(m\) 次修改操作 x y z ,表示将第 \(x\) 个序列的第 \(y\) 个数修改为 \(z\) 。
输出修改前和每次修改后的答案对 \(19260817\) 取模的结果。
数据范围
- \(1\le n,m,\sum|len_i|\le 10^5\) 。
- \(1\le x\le n,1\le y\le len_x\) ,保证任何时刻序列中的元素均为
int型整数。
时间限制 \(\texttt{1.5s}\) ,空间限制 \(\texttt{125MB}\) 。
分析
显然可以把贡献拆到每个元素上。
- \(f_{i,x}\) (
vector类型)存储第 \(i\) 个序列中 \(x\) 的所有出现位置。 - \(g_{i,x}=\sum\binom{f_{i,x,j}-f_{i,x,j-1}}2\) 为从第 \(i\) 个序列中选择一个不含 \(x\) 的方案数。
- \(h_x=\prod_{i=1}^ng_{i,x}\) 。
则最终答案为:
\[res=\sum\left(\frac{len_i(len_i+1)}2-h_x\right)\\
\]
容易发现修改只会对 \(\mathcal O(1)\) 个值产生影响。先倒序撤销对 \(res\) 的贡献,再正序更新即可。
为了解决 \(h_x\) 乘除 \(0\) 的问题,将 \(h_x\) 维护成 \(v\cdot 0^c\) 的形式,其中 \(v\neq 0\) 。
时间复杂度 \(\mathcal O(n\log n)\) ,细节较多。
#include<bits/stdc++.h>
#define fi first
#define se second
#define mp make_pair
#define pii pair<int,int>
using namespace std;
const int maxn=1e5+5,mod=19260817;
int m,n,x,y,z,all=1,res;
int l[maxn];
vector<int> vec[maxn];
map<int,set<int>> f[maxn];
map<int,int> g[maxn];
int qpow(int a,int k)
{
int res=1;
for(;k;a=1ll*a*a%mod,k>>=1) if(k&1) res=1ll*res*a%mod;
return res;
}
struct num
{
int o,x;
num()
{
o=0,x=all;
}
int val()
{
return o?0:x;
}
};
void operator*=(num &a,int b)
{
b?a.x=1ll*a.x*b%mod:a.o++;
}
void operator/=(num &a,int b)
{
b?a.x=1ll*a.x*qpow(b,mod-2)%mod:a.o--;
}
map<int,num> h;
void inc(int &x,int y)
{
if((x+=y)>=mod) x-=mod;
}
void dec(int &x,int y)
{
if((x-=y)<0) x+=mod;
}
int c(int x)
{
return x*(x-1ll)/2%mod;
}
void del(int i,int j)
{
int x=vec[i][j];
auto &s=f[i][x];
auto r=s.erase(s.find(j)),l=prev(r);
inc(res,h[x].val()),h[x]/=g[i][x];
dec(g[i][x],c(j-*l)),dec(g[i][x],c(*r-j)),inc(g[i][x],c(*r-*l));
h[x]*=g[i][x],dec(res,h[x].val());
}
void add(int i,int j)
{
int x=vec[i][j];
if(g[i].find(x)==g[i].end()) f[i][x].insert(-1),f[i][x].insert(l[i]),g[i][x]=c(l[i]+1);
auto &s=f[i][x];
auto it=s.insert(j).fi,l=prev(it),r=next(it);
inc(res,h[x].val()),h[x]/=g[i][x];
inc(g[i][x],c(j-*l)),inc(g[i][x],c(*r-j)),dec(g[i][x],c(*r-*l));
h[x]*=g[i][x],dec(res,h[x].val());
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&l[i]),all=1ll*all*c(l[i]+1)%mod;
for(int i=1;i<=n;i++)
{
vec[i].resize(l[i]);
for(int j=0;j<l[i];j++) scanf("%d",&vec[i][j]),f[i][vec[i][j]].insert(j);
for(auto &p:f[i])
{
int x=p.fi,cur=0;
auto &s=p.se;
s.insert(-1),s.insert(l[i]);
for(auto it=s.begin();it!=s.end();++it) if(it!=s.begin()) inc(cur,c(*it-*prev(it)));
g[i][x]=cur,h[x]/=c(l[i]+1),h[x]*=cur;
}
}
res=1ll*h.size()*all%mod;
for(auto &p:h) dec(res,p.se.val());
printf("%d\n",res);
while(m--)
{
scanf("%d%d%d",&x,&y,&z),del(x,--y),vec[x][y]=z,add(x,y);
printf("%d\n",res);
}
return 0;
}
本文来自博客园,作者:peiwenjun,转载请注明原文链接:https://www.cnblogs.com/peiwenjun/p/18702223
浙公网安备 33010602011771号