11.21 比赛总结
100+10+10+100,rk2。
T1 图
简单题,\(bitset\) 即可。时间复杂度 \(O(\frac{n^2m}{\omega})\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=10005;
int n,m,ans;string st;
bitset<N>ed[N],s,t,k;
signed main(){
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
while(m--){
cin>>st;
for(int i=0;i<n;i++){
s[i]=(st[i]=='2');
t[i]=(st[i]=='1');
k[i]=(st[i]=='3');
}for(int i=0;i<n;i++){
if(s[i]) ed[i+1]^=t|k;
if(t[i]) ed[i+1]^=s|k;
if(k[i]) ed[i+1]^=s|t|k;
}for(int i=0;i<n;i++)
s[i]=t[i]=k[i]=0;
}for(int i=1;i<=n;i++)
for(int j=0;j<n;j++)
ans+=(i-1!=j)*ed[i][j];
cout<<ans/2;
return 0;
}
T2 序列
考虑每个位置赋值只能进行一次,直接将赋值转化为加法;同一位置上的加法肯定先加大后加小,那么 \(g_{i,j}\) 的贡献就是给原序列 \(\times \frac{g_{i,j}+a'_i}{a'_i}\),然后 \(a'_i\gets a'_i+g_{i,j}\),这样就将加法转化为乘法。最后前缀积即可。
#include<bits/stdc++.h>
#define db double
#define int long long
using namespace std;
const int N=1e5+5;
const int p=1e9+7;
int qpow(int x,int y){
int re=1;
while(y){
if(y&1) re=re*x%p;
x=x*x%p,y>>=1;
}return re;
}int n,m,k,a[N],nw;
vector<int>g[N];int mx[N];
struct chg{int x,y;}ly[N];
int cmp(chg x,chg y){
return (db)x.x*y.y>(db)y.x*x.y;
}int cmp1(int x,int y){
return x>y;
}signed main(){
freopen("b.in","r",stdin);
freopen("b.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m,nw=1;
for(int i=1;i<=n;i++)
cin>>a[i],nw=nw*a[i]%p;
for(int i=1;i<=m;i++){
int opt,x,y;cin>>opt>>x>>y;
if(opt==1) mx[x]=max(mx[x],y);
if(opt==2) g[x].push_back(y);
if(opt==3) ly[++k]={y,1};
}for(int i=1;i<=n;i++){
if(!g[i].size()&&mx[i]<=a[i]) continue;
if(mx[i]>a[i])
g[i].push_back(mx[i]-a[i]);
sort(g[i].begin(),g[i].end(),cmp1);
int lyh=a[i];
for(auto x:g[i])
ly[++k]={lyh+x,lyh},lyh+=x;
}sort(ly+1,ly+k+1,cmp);
ly[0].x=ly[0].y=1;
for(int i=0;i<=m;i++){
if(i>k){cout<<nw<<" ";continue;}
nw=nw*ly[i].x%p*qpow(ly[i].y,p-2)%p;
cout<<nw<<" ";
}return 0;
}
T3 树
大离谱题,每个人的 \(AC\) 代码都可以在一组手造数据上跑出不一样的风采,输出 \(n^{2d}\) 能得 \(90pts\)……题解没看懂,就贴代码了。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+5;
const int p=1e9+7;
struct cat6{
int xzz[2][2];
cat6(){memset(xzz,0,sizeof(xzz));}
}a,b;vector<int>g[N];
int n,k,f1[N],f2[N],g1[N];
int m,g2[N],sr[N][2],s[N];
cat6 operator*(cat6 x,cat6 y){
cat6 z;
for(int i=0;i<2;i++) for(int j=0;j<2;j++) for(int l=0;l<2;l++)
z.xzz[i][j]=(z.xzz[i][j]+x.xzz[i][l]*y.xzz[l][j])%p;
return z;
}cat6 qpow(cat6 x,int y){
cat6 re;
re.xzz[0][0]=re.xzz[1][1]=1;
while(y){
if(y&1) re=re*x;
x=x*x,y>>=1;
}return re;
}void dfs1(int x,int fa){
for(auto y:g[x]) if(y!=fa)
dfs1(y,x),s[x]+=!f1[y],sr[x][f1[y]]+=g1[y];
f1[x]=(s[x]>0);
if(!s[x]) g1[x]=sr[x][1]+1;
if(s[x]==1) g1[x]=sr[x][0];
}void dfs2(int x,int fa){
m+=(!f1[x]);
g2[x]=g1[x],f2[x]=f1[x];
for(int y:g[x]){
if(y==fa) continue;
int sx=s[x],fx=f1[x],gx=g1[x];
int szx=sr[x][0],sox=sr[x][1];
int sy=s[y],fy=f1[y],gy=g1[y];
int szy=sr[y][0],soy=sr[y][1];
s[x]-=!f1[y],f1[x]=(s[x]>0);
sr[x][f1[y]]-=g1[y];
if(s[x]==1) g1[x]=sr[x][0];
if(!s[x]) g1[x]=sr[x][1]+1;
if(s[x]>1) g1[x]=0;
f1[y]|=!f1[x],s[y]+=!f1[x];
sr[y][f1[x]]+=g1[x];
if(s[y]==1) g1[y]=sr[y][0];
if(!s[y]) g1[y]=sr[y][1]+1;
if(s[y]>1) g1[y]=0;dfs2(y,x);
s[x]=sx,f1[x]=fx,g1[x]=gx;
sr[x][0]=szx,sr[x][1]=sox;
s[y]=sy,f1[y]=fy,g1[y]=gy;
sr[y][0]=szy,sr[y][1]=soy;
}
}signed main(){
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;int ans=0;
for(int i=1,x,y;i<n;i++){
cin>>x>>y;
g[x].push_back(y);
g[y].push_back(x);
}dfs1(1,0),dfs2(1,0);
for(int i=1;i<=n;i++){
if(!f2[i]){
b.xzz[1][0]=(b.xzz[1][0]+n)%p;
b.xzz[0][0]=(b.xzz[0][0]+n-g2[i])%p;
b.xzz[0][1]=(b.xzz[0][1]+g2[i])%p;
}if(f2[i]==1){
b.xzz[0][0]=(b.xzz[0][0]+g2[i])%p;
b.xzz[0][1]=(b.xzz[0][1]+n-g2[i])%p;
b.xzz[1][1]=(b.xzz[1][1]+n)%p;
}
}a.xzz[0][0]=m,a.xzz[0][1]=n-m;
a=a*qpow(b,k-1);
int ly=a.xzz[0][0],wz=a.xzz[0][1];
if(f1[1]) cout<<((n-g2[1])*ly%p+n*wz%p+p+p)%p;
else cout<<g2[1]*ly%p;
return 0;
}
D 字符串
个人感觉难度应该放 \(B/C\)。
容易发现相邻点对只有 \(100\) 种情况,且种内填充字符数相同。用线段树维护相邻点对即可。时间复杂度 \(O(k^2m\log n+k^2n)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,M=8e5+5;
int n,m,k,sm[M][10][10],rs=-1;string s;
int tmp[10][10],kmp[10][10],lc[M],rc[M],fl[M];
void push_up(int x){
for(int i=0;i<k;i++) for(int j=0;j<k;j++)
sm[x][i][j]=sm[x*2][i][j]+sm[x*2+1][i][j];
lc[x]=lc[x*2],rc[x]=rc[x*2+1];
sm[x][rc[x*2]][lc[x*2+1]]++;
}void pd(int x,int c){
for(int i=0;i<k;i++)
for(int j=0;j<k;j++)
tmp[i][j]=sm[x][i][j];
for(int i=0;i<k;i++) for(int j=0;j<k;j++)
sm[x][(i+c)%k][(j+c)%k]=tmp[i][j],tmp[i][j]=0;
lc[x]=(lc[x]+c)%k,fl[x]=(fl[x]+c)%k;
rc[x]=(rc[x]+c)%k;
}void push_down(int x){
if(!fl[x]) return;
pd(x*2+1,fl[x]);
pd(x*2,fl[x]),fl[x]=0;
}void add(int x){
for(int i=0;i<k;i++)
for(int j=0;j<k;j++)
kmp[i][j]+=sm[x][i][j];
if(~rs) kmp[rs][lc[x]]++;
rs=rc[x];
}void build(int x,int l,int r){
if(l==r){
lc[x]=rc[x]=s[l]-'a';
return;
}int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
push_up(x);
}void chg(int x,int l,int r,int L,int R,int c){
if(L<=l&&r<=R)
return pd(x,c),void();
push_down(x);
int mid=(l+r)/2;
if(L<=mid) chg(x*2,l,mid,L,R,c);
if(R>mid) chg(x*2+1,mid+1,r,L,R,c);
push_up(x);
}void gadd(int x,int l,int r,int L,int R){
if(L<=l&&r<=R)
return add(x),void();
push_down(x);
int mid=(l+r)/2;
if(L<=mid) gadd(x*2,l,mid,L,R);
if(R>mid) gadd(x*2+1,mid+1,r,L,R);
}int gch(int x,int l,int r,int v){
if(l==r) return lc[x];
int mid=(l+r)/2;push_down(x);
if(v<=mid) return gch(x*2,l,mid,v);
return gch(x*2+1,mid+1,r,v);
}signed main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m>>k>>s;
s=" "+s,build(1,1,n);
while(m--){
int opt;cin>>opt;
if(opt==1){
int l,r,c;cin>>l>>r>>c;
chg(1,1,n,l,r,c);continue;
}int l,r;cin>>l>>r>>s;
gadd(1,1,n,l,r);int ans=0;
for(int i=0;i<k;i++)
for(int j=0;j<k;j++){
int ln=((i==j)?k:(j-i+k)%k);
ans+=kmp[s[i]-'a'][s[j]-'a']*ln;
kmp[s[i]-'a'][s[j]-'a']=0;
}
int ch=gch(1,1,n,l);
for(int i=0;i<k;i++)
if(s[i]-'a'==ch) ans+=i;
ch=gch(1,1,n,r);
for(int i=0;i<k;i++)
if(s[i]-'a'==ch) ans+=k-i;
cout<<ans/k<<"\n",rs=-1;
}return 0;
}