20210620省队互测-qwaszx 题解
T1
其他四重原题分别是
Codechef FRBSUM
FJOI2016 神秘数
19 ICPC 徐州 H
21 ICPC 昆明 M
其中徐州那个是带修的,其他是不带修的. 不带修的情况下通过分散层叠和线性 rmq 我们可以做到
首先考虑静态全局询问情况下如何求出答案,从小到大排序,依次加入,维护当前能表示的极长前缀
一个自然的想法是暴力做这个过程,每次加入所有
上面这个做法看起来没什么救,我们考虑把值域按
下面认为
代码是线性空间的做法.
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int INF=1e9+500;
const int N=530000;
struct Node
{
long long s[30];int mi[30];
Node(){}
Node(const int &x)
{
int id=31-__builtin_clz(x);
for(int i=0;i<30;i++)s[i]=0,mi[i]=INF;
s[id]=mi[id]=x;
}
void clear(){for(int i=0;i<30;i++)s[i]=0,mi[i]=INF;}
}a[(N/30)<<1];
int n,w[N],qn;
Node operator +(const Node &a,const Node &b)
{
Node ans;
for(int i=0;i<30;i++)ans.s[i]=a.s[i]+b.s[i];
for(int i=0;i<30;i++)ans.mi[i]=min(a.mi[i],b.mi[i]);
return ans;
}
void build(int rot,int lt,int rt)
{
if(rt-lt+1<=32)
{
a[rot].clear();
for(int i=lt;i<=rt;i++)
{
int id=31-__builtin_clz(w[i]);
a[rot].s[id]+=w[i],a[rot].mi[id]=min(a[rot].mi[id],w[i]);
}
return;
}
if(lt==rt){a[rot]=Node(w[lt]);return;}
int mid=(lt+rt)>>1;
build(rot<<1,lt,mid),build(rot<<1|1,mid+1,rt);
a[rot]=a[rot<<1]+a[rot<<1|1];
}
void update(int rot,int lt,int rt,int q,int tw)
{
if(rt-lt+1<=32)
{
a[rot].clear();
w[q]=tw;
for(int i=lt;i<=rt;i++)
{
int id=31-__builtin_clz(w[i]);
a[rot].s[id]+=w[i],a[rot].mi[id]=min(a[rot].mi[id],w[i]);
}
return;
}
int mid=(lt+rt)>>1;
if(q<=mid)update(rot<<1,lt,mid,q,tw);
else update(rot<<1|1,mid+1,rt,q,tw);
// int id=31-__builtin_clz(tw);
// a[rot].s[id]=a[rot<<1].s[id]+a[rot<<1|1].s[id];
// a[rot].mi[id]=min(a[rot<<1].mi[id],a[rot<<1|1].mi[id]);
a[rot]=a[rot<<1]+a[rot<<1|1];
}
Node query(int rot,int lt,int rt,int lq,int rq)
{
if(rt-lt+1<=32)
{
Node ans;ans.clear();
for(int i=max(lt,lq);i<=rt&&i<=rq;i++)
{
int id=31-__builtin_clz(w[i]);
ans.s[id]+=w[i],ans.mi[id]=min(ans.mi[id],w[i]);
}
return ans;
}
if(lt>=lq&&rt<=rq)return a[rot];
int mid=(lt+rt)>>1;
if(rq<=mid)return query(rot<<1,lt,mid,lq,rq);
if(lq>mid)return query(rot<<1|1,mid+1,rt,lq,rq);
return query(rot<<1,lt,mid,lq,rq)+query(rot<<1|1,mid+1,rt,lq,rq);
}
int getin()
{
int x=0;char ch=getchar();
while(ch<'0'||ch>'9')ch=getchar();
while(ch>='0'&&ch<='9')x=x*10+ch-48,ch=getchar();
return x;
}
int main()
{
// freopen("data.txt","r",stdin);
// freopen("cswa.txt","w",stdout);
n=getin(),qn=getin();
for(int i=1;i<=n;i++)w[i]=getin();
build(1,1,n);
for(int i=1,opt,l,r;i<=qn;i++)
{
opt=getin(),l=getin(),r=getin();
if(opt==1)update(1,1,n,l,r);
else
{
Node t=query(1,1,n,l,r);
long long sum=0;
for(int j=0;j<30;j++)
{
if(!t.s[j])continue;
if(t.mi[j]<=sum+1)sum+=t.s[j];
}
printf("%lld\n",sum+1);
}
}
}
T2
定义一个
给定
原题来自一轮集训 nealchen 的课件,把
所求即用长度小于
解出
我们枚举段数
现在我们只需要知道如何快速计算上式. 令
那么我们要计算
代入
令
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<vector>
#include<algorithm>
using namespace std;
const int mod=1000000007;
const int N=5e6+500;
int qmod1(const int &x){return x>=mod?x-mod:x;}
int qmod2(const int &x){return x+(x>>31&mod);}
int n,m;
int f[N];
typedef vector<pair<int,int> > Poly;
Poly a1,a2,a3,A,B;
Poly simplify(Poly tans)
{
sort(tans.begin(),tans.end());
Poly ans;
for(int i=0;i<tans.size();i++)
{
if(!tans[i].second)continue;
if(!ans.size()||tans[i].first!=(--ans.end())->first)
ans.push_back(tans[i]);
else
{
(--ans.end())->second=qmod1((--ans.end())->second+tans[i].second);
if(!(--ans.end())->second)ans.pop_back();
}
}
return ans;
}
Poly Der(const Poly &a)
{
Poly ans;
for(int i=0;i<a.size();i++)
if(a[i].first)ans.push_back(make_pair(a[i].first-1,1ll*a[i].first*a[i].second%mod));
return ans;
}
Poly operator -(const Poly &a,const Poly &b)
{
Poly tans=a;
for(int i=0;i<b.size();i++)tans.push_back(make_pair(b[i].first,qmod2(-b[i].second)));
return simplify(tans);
}
Poly operator *(const Poly &a,const Poly &b)
{
Poly tans;
for(int i=0;i<a.size();i++)for(int j=0;j<b.size();j++)
tans.push_back(make_pair(a[i].first+b[j].first,1ll*a[i].second*b[j].second%mod));
return simplify(tans);
}
Poly operator >>(const Poly &a,const int &b)
{
Poly ans;
for(int i=0;i<a.size();i++)
ans.push_back(make_pair(a[i].first-b,a[i].second));
return ans;
}
void print(const Poly &a)
{
for(int i=0;i<a.size();i++)
{
if(i)putchar('+');
printf("%d",a[i].second);
if(a[i].first)printf("x^%d",a[i].first);
}
puts("");
}
int main()
{
freopen("data.txt","r",stdin);
freopen("cswa.txt","w",stdout);
scanf("%d%d",&n,&m);
A.resize(3);
A[0]=make_pair(1,1),A[1]=make_pair(m,mod-2),A[2]=make_pair(m+1,1);
B.resize(2);
B[0]=make_pair(0,1),B[1]=make_pair(m,mod-1);
a1=A*A*B;
a2=(B-A)*(Der(A)*B-A*Der(B));
a3=B*(A*Der(B)-B*Der(A));
for(int i=0;i<a3.size();i++)
{
if(a3[i].first>n)break;
f[a3[i].first]=qmod2(-a3[i].second);
}
// print(a1),print(a2),print(a3);
for(int i=0;i<=n;i++)
{
int t=0;
for(int j=0,k;j<a1.size()&&(k=i-a1[j].first+1)>=0;j++)
t=(t+1ll*a1[j].second*k%mod*f[k])%mod;
for(int j=1,k;j<a2.size()&&(k=i-a2[j].first)>=0;j++)
t=(t-1ll*a2[j].second*f[k])%mod;
f[i]=(0ll+f[i]+t+mod)%mod;
// cout<<f[i]<<",";
}
cout<<f[n]<<endl;
}
T3
原题是正睿 21 省选十连测 day7T2,把
按照题意,写出前
现在来考察
首先写出等比数列求和的封闭形式
注意分子分母都是有漂亮的形式的,这个乘积可以展开为:
其中
这个展开式可以这样获得:以分母为例,令
注意到
按第二维展开可以获得系数的递推式.
接下来,枚举左右的求和指标
暴力枚举所有的求和指标并对每个
上面是我场上写的做法. 还有一个更简单也更一般的做法. 直接考虑设
由
虽然下面这个做法看起来优秀得多,但实际跑起来差不多(因为瓶颈其实在线性递推)
代码去掉了板子
//sol1
Poly qfac[105][105];
int n,X,Y,K,L;
Z calcall()
{
Poly a;a.resize(n+1);
for(int i=0;i<K;i++)a[i]=1;
Poly g;g.resize(n+1);
g[0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=i;j++)g[i+1]+=Z(X)*Z(j+1)*a[j+1]*g[i-j];
for(int j=0;j<i;j++)g[i+1]-=Z(j+1)*g[j+1]*a[i-j];
g[i+1]*=Z(i+1).inv();
}
return g[n];
}
Poly comK(const Poly &a)
{
Poly ans;ans.resize((a.size()-1)*K+1);
for(int i=0;i<a.size();i++)
ans[i*K]=a[i];
return ans;
}
struct FRAC
{
Poly fz,fm;
int u1,u2,v1,v2;
void clear(){fz=Poly(0),fm=Poly(1),u1=u2=v1=v2=0;}
void ins(int tu1,int tu2,int tv1,int tv2)
{
Poly t0=Poly((tu1+tv1)%2?-1:1)<<(tu1*(tu1-1)/2+tv1*(tv1-1)/2*K);
if(tu1>tu2)swap(tu1,tu2);
if(tv1>tv2)swap(tv1,tv2);
int ru1=max(u1,tu1),ru2=max(u2,tu2);
int rv1=max(v1,tv1),rv2=max(v2,tv2);
Poly d=qfac[u1+1][ru1]*qfac[u2+1][ru2]*comK(qfac[v1+1][rv1]*qfac[v2+1][rv2]);
fm*=d;
fz*=d;
u1=ru1,u2=ru2,v1=rv1,v2=rv2;
fz+=qfac[tu1+1][ru1]*qfac[tu2+1][ru2]*comK(qfac[tv1+1][rv1]*qfac[tv2+1][rv2])*t0;
// print(fz),print(fm);puts("");
}
}h[100];
Z calc(int s,int tp)
{
Z ans=0;
using namespace Recursive;
for(int i=0;i<=n&&1ll*i*X<=s;i++)
{
// cout<<i<<":"<<endl;
// print(h[i].fz),print(h[i].fm);
// puts("");
if(tp==0)ans+=Liner(h[i].fz,h[i].fm*Poly(1,-1),s-i*X);
else ans+=Liner(Poly(i*X)*h[i].fz*h[i].fm+((Der(h[i].fz)*h[i].fm-h[i].fz*Der(h[i].fm))<<1),Poly(1,-1)*h[i].fm*h[i].fm,s-i*X);
}
return ans;
}
void prework(int n)
{
for(int l=1;l<=n+1;l++)
{
qfac[l][l-1]=Poly(1);
for(int r=l;r<=n;r++)
{
qfac[l][r]=qfac[l][r-1];qfac[l][r].resize(qfac[l][r].size()+r);
for(int i=qfac[l][r].size()-1;i>=r;i--)
qfac[l][r][i]-=qfac[l][r][i-r];
}
}
for(int i=0;i<=n;i++)h[i].clear();
for(int j=0;j*K<=n&&j<=X;j++)
{
int i=n-j*K;
for(int u=0;u<=i;u++)
for(int v=0;v<=j;v++)
h[u+(j-v)*K].ins(u,i-u,v,j-v);
}
}
int main()
{
freopen("data.txt","r",stdin);
// freopen("cswa.txt","w",stdout);
scanf("%d%d%d%d%d",&n,&L,&Y,&X,&K);
++X,++K;--n;
prework(n);
Z ans=Z(L-Y+1)*calcall();
ans-=Z(L+1)*calc(L,0);
ans+=Z(Y)*calc(Y,0);
ans+=calc(L,1)-calc(Y,1);
print(ans);puts("");
}
//sol2
Poly qfac[105][105];
int n,X,Y,K,L;
Z calcall()
{
Poly a;a.resize(n+1);
for(int i=0;i<K;i++)a[i]=1;
Poly g;g.resize(n+1);
g[0]=1;
for(int i=0;i<n;i++)
{
for(int j=0;j<=i;j++)g[i+1]+=Z(X)*Z(j+1)*a[j+1]*g[i-j];
for(int j=0;j<i;j++)g[i+1]-=Z(j+1)*g[j+1]*a[i-j];
g[i+1]*=Z(i+1).inv();
}
return g[n];
}
Poly f[100][100],df[100];
Z calc(int s,int tp)
{
Z ans=0;
using namespace Recursive;
for(int i=0;i<=n&&1ll*i*X<=s;i++)
{
// print(f[n][i]);
if(tp==0)ans+=Liner(f[n][i],qfac[1][n]*Poly(1,-1),s-i*X);
else ans+=Liner(df[i],Poly(1,-1)*qfac[1][n]*qfac[1][n],s-i*X);
}
return ans;
}
void prework(int n)
{
for(int l=1;l<=n+1;l++)
{
qfac[l][l-1]=Poly(1);
for(int r=l;r<=n;r++)
{
qfac[l][r]=qfac[l][r-1];qfac[l][r].resize(qfac[l][r].size()+r);
for(int i=qfac[l][r].size()-1;i>=r;i--)
qfac[l][r][i]-=qfac[l][r][i-r];
}
}
f[0][0]=Poly(1);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=i-1;j++)
f[i][j]+=f[i-1][j];
for(int j=0;j<=i-1;j++)
f[i][j+1]-=f[i-1][j]<<(i-1);
if(i>=K)
{
for(int j=0;j<=i-K;j++)
f[i][j+K]+=f[i-K][j]*qfac[i-K+1][i-1];
for(int j=0;j<=i-K;j++)
f[i][j]-=f[i-K][j]*qfac[i-K+1][i-1]<<(i-K);
}
if(i>=K+1)
{
for(int j=0;j<=i-K-1;j++)
f[i][j+K]-=f[i-K-1][j]*qfac[i-K][i-1];
for(int j=0;j<=i-K-1;j++)
f[i][j+1]+=f[i-K-1][j]*qfac[i-K][i-1]<<(i-K-1);
}
}
for(int i=0;i<=n;i++)df[i]=Poly(i*X)*f[n][i]*qfac[1][n]+((Der(f[n][i])*qfac[1][n]-f[n][i]*Der(qfac[1][n]))<<1);
}
int main()
{
freopen("data.txt","r",stdin);
// freopen("cswa.txt","w",stdout);
scanf("%d%d%d%d%d",&n,&L,&Y,&X,&K);
++X,++K;--n;
prework(n);
Z ans=Z(L-Y+1)*calcall();
ans-=Z(L+1)*calc(L,0);
// cout<<calc(L,0)<<endl;
ans+=Z(Y)*calc(Y,0);
ans+=calc(L,1)-calc(Y,1);
print(ans);puts("");
}