2023.1.19
ARC104F Visibility Sequence
题意:有 \(n\) 栋楼,第 \(i\) 栋楼的高度 \(h_i\) 在 \([1,x_i]\) 中随机。对于 \(i\in [1,n]\) 定义 \(p_i\) 为若 \(h_i\) 为前缀最大值则 \(p_i=-1\),否则 \(p_i\) 为前面离 \(i\) 最近的比 \(i\) 高的位置。求 \(p\) 的种类数。
题解:不难,直接过了。这个数据范围,必然是区间 \(dp\)。本来我还考虑前缀最大值划分,既然是区间 \(dp\),那直接上最大值划分就好了。令 \(k\) 为区间 \([l,r]\) 的最后一个最大值的位置,那么 \([k+1,r]\) 的取值必须小于 \(h_k\),所以 \(p\) 也不小于 \(k\),是一个子结构,前缀当然也是一个子结构。设 \(dp_{l,r,v}\) 表示区间 \([l,r]\) 内 \(h\) 取值不大于 \(v\) 的答案。然而 \(v\) 很大,然而发现 \(v\) 一定可以表示为 \(x_a-b\),其中 \(a,b\leqslant n\),于是直接 \(O(n^4)\) 就过了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
const int N=105;
int dp[N][N][N][N];bool vis[N][N][N][N];
int n,a[N];
inline int dfs(int l,int r,int p,int dt){
if(l>r)return 1;if(a[p]==dt)return 0;
if(vis[l][r][p][dt])return dp[l][r][p][dt];
vis[l][r][p][dt]=true;int res=0;
for(int k=l;k<=r;k++)
if(a[p]-dt>=a[k])res=(res+1ll*dfs(l,k-1,k,0)*dfs(k+1,r,k,1))%mod;
else res=(res+1ll*dfs(l,k-1,p,dt)*dfs(k+1,r,p,dt+1))%mod;
dp[l][r][p][dt]=res;return res;
}
int main(){
n=read();a[0]=inf;
for(int i=1;i<=n;i++)a[i]=read();
printf("%d\n",dfs(1,n,0,0));
return 0;
}
CF1621G Weighted Increasing Subsequences
题意:给定一个序列,定义其一个上升子序列的权值为存在一个在末尾之后的比其更大的数的个数,求权值和。
题解:很有意思。容易想到“在末尾之后更大的数”就是最大值,一开始想要以最大值作为突破点,发现不行。于是考虑常用的:每个点的贡献。
注意到一个点有贡献当且仅当末尾在最后一个大于它的之前。设以此点为结尾的个数为 \(f_i\),为开头的个数为 \(g_i\),则其贡献为 \(f_i(g_i-\text{两点之间的个数})\)。
注意到这个点和比它大的若干点的最远点都是这个,而上升子序列的开头和结尾就是这两个,于是值域固定了,于是求一遍就求出了这个点和比它大的若干点的答案。
于是我们就成功的均摊成为了 \(O(n\log n)\)。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
int n,m,T,a[maxn],b[maxn],tr[maxn],F[maxn],G[maxn];
inline void Add(int &x,int y){x=(x+y>=mod?x+y-mod:x+y);}
inline void add(int x,int y){
for(;x<=n;x+=x&(-x))Add(tr[x],y);
}
inline void clear(int x){
for(;x<=n;x+=x&(-x))tr[x]=0;
}
inline int query(int x){
int res=0;
for(;x;x-=x&(-x))Add(res,tr[x]);
return res;
}
vector<int>P[maxn];
int st[maxn],top,dp[maxn];
inline void solve(){
n=read();int ans=0,Mx=1;
for(int i=1;i<=n;i++)a[i]=b[i]=read();
sort(b+1,b+1+n);
b[0]=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+b[0],a[i])-b;
// for(int i=1;i<=n;i++)
// printf("%d ",a[i]);puts("");
for(int i=1;i<=n;i++)tr[i]=F[i]=G[i]=0;
for(int i=1;i<=n;i++)
F[i]=1+query(a[i]-1),add(a[i],F[i]);
for(int i=1;i<=n;i++)tr[i]=0;
for(int i=n;i>=1;i--)
G[i]=1+query(n-a[i]),add(n-a[i]+1,G[i]);
for(int i=1;i<=n;i++)tr[i]=0;
for(int i=1;i<=n;i++)P[i].clear();
for(int i=1;i<=n;i++)P[a[i]].push_back(i);
for(int i=n;i>=1;i--)if(a[i]>Mx){
top=0;
for(int j=Mx;j<a[i];j++)
for(auto x:P[j])st[++top]=x;
sort(st+1,st+1+top);
for(int j=top;j>=1;j--){
if(st[j]>i)continue;int p=st[j];
dp[p]=1+query(n-a[p]);
add(n-a[p]+1,dp[p]);
ans=(ans+1ll*F[p]*(G[p]-dp[p]+mod))%mod;
}Mx=a[i];
for(int j=1;j<=top;j++)clear(n-a[st[j]]+1);
}printf("%d\n",ans);
}
int main(){
T=read();
while(T--)solve();
return 0;
}
CF1747E List Generation
弱智题,但没办法,我就是弱智,于是做不出。
题解:容易想到 \(O(n^2)\) 的容斥:
令 \(F_i=\binom{i+n-1}{n}\binom{i+m-1}{m}\),替换一下,则有:
后面那坨要是不能递推就来了鬼了。
根据 EI 的说法,两个 EGF 卷积的前缀和没办法线性求,所以肯定是考察一个特殊的。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int mod=1e9+7;
#define inf 1e9
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
return x*f;
}
inline int ksm(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%mod;
x=1ll*x*x%mod;y>>=1;
}return res;
}
const int M=1e7;
const int N=2e7;
int fac[N+5],ifc[N+5];
int T,n,m,F[M+5],G[M+5];
inline int com(int x,int y){
if(x<0||y<0||x<y)return 0;
return 1ll*fac[x]*ifc[y]%mod*ifc[x-y]%mod;
}
int main(){
fac[0]=ifc[0]=1;
for(int i=1;i<=N;i++)fac[i]=1ll*fac[i-1]*i%mod;
ifc[N]=ksm(fac[N],mod-2);
for(int i=N-1;i>=1;i--)
ifc[i]=1ll*ifc[i+1]*(i+1)%mod;
T=read();while(T--){
n=read(),m=read();int ans=0,op=((n+m)%2?1:mod-1);G[n+m+1]=op;
for(int i=1;i<=n+m;i++)F[i]=1ll*com(i+n-1,n)*com(i+m-1,m)%mod;
for(int i=n+m;i>=0;i--)G[i]=((1ll*op*com(n+m+2,i+1)-G[i+1]-G[i+1])%mod+mod)%mod;
for(int i=0;i<=n+m;i++){
int o=((i&1)?1:mod-1);
ans=(ans+1ll*o*F[i]%mod*(i+1)%mod*G[i+1])%mod;
}printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号