题解:P16433 [APIO 2026 中国赛区] 上升
赛场上 2.5h 过了这道题(最终收获铜牌),乱写的
首先考虑
然后考虑拓展这个写法,我们发现如果它给定了这个
我们记
但是对于想填大于
所以就有一个状态
这个转移是比较容易的,时间复杂度是
有些许卡常。
Code
#include<bits/stdc++.h>
#define ll int
#define fi first
#define se second
#define pii pair<int,int>
#define ls(x) ((x)*2)
#define rs(x) ((x)*2+1)
#define Debug(...) fprintf(stderr, __VA_ARGS__)
#define For(i,a,b) for(int i=a,i##end=b;i<=i##end;i++)
#define Rof(i,a,b) for(int i=a,i##end=b;i>=i##end;i--)
#define rep(i, b) for(int i=1,i##end=b;i<=i##end;i++)
using namespace std;
const int N=1e6+5;
ll p[N],w[N],Mod;
ll lst[N],pre[N];
ll dp[2][505][505][2],qzh[505][505][2];
ll C[505][505];
#define Add(x,y) (x+y>=Mod?x+=y-Mod:x+=y)
#define work(j,l,r,c,w) ((l<=r)?(Add(qzh[j][l][c],w),Add(qzh[j][r+1][c],Mod-w),vis[j]=1):0)
bool vis[N];
int ascend(int c, int n, int MM, std::vector<int> P, std::vector<int> W){
P.push_back(n+1);Mod=MM;
C[0][0]=1;
For(i,1,500){
C[i][0]=1;
For(j,1,i) (C[i][j]=(C[i-1][j-1]+C[i-1][j]))%=Mod;
}
For(i,1,n+1)p[i]=P[i-1];
For(i,1,n-1)w[i]=W[i-1];
For(i,1,n){
if(p[i]) lst[i]=p[i];
else lst[i]=lst[i-1];
}
For(j,0,n)For(t,0,n)For(c,0,1)For(i,0,1)dp[i][j][t][c]=0;
if(p[1]) dp[1][p[1]-1][p[1]-1][0]=1;
else dp[1][0][1][1]=1;
For(i,1,n) pre[i]=pre[i-1]+(p[i]>0);
For(i,2,n){
For(j,0,lst[i])For(t,0,n)For(c,0,1)dp[i&1][j][t][c]=qzh[j][t][c]=0;
if(!p[i]){
For(t,0,n) vis[t]=0;
//0
For(j,0,lst[i-1])For(t,0,n)if(n-lst[i-1]>=i-1-(lst[i-1]-j)&&dp[(i-1)&1][j][t][0]){
work(j-1,0,t-1,0,dp[(i-1)&1][j][t][0]);
work(j-1,t,j-1,0,1ll*dp[(i-1)&1][j][t][0]*w[i-1]%Mod);
work(j,lst[i-1]-j+1,i,1,1ll*dp[(i-1)&1][j][t][0]*w[i-1]%Mod);
}
//1
For(j,0,lst[i-1])For(t,0,n)if(n-lst[i-1]>=i-1-(lst[i-1]-j)&&dp[(i-1)&1][j][t][1]){
work(j-1,0,j-1,0,dp[(i-1)&1][j][t][1]);
work(j,lst[i-1]-j+1,t,1,dp[(i-1)&1][j][t][1]);
work(j,t+1,i,1,1ll*dp[(i-1)&1][j][t][1]*w[i-1]%Mod);
}
For(j,0,lst[i])if(vis[j])For(t,1,n)For(c,0,1)Add(qzh[j][t][c],qzh[j][t-1][c]);
For(j,0,lst[i])if(vis[j])For(t,0,n)For(c,0,1)Add(dp[i&1][j][t][c],qzh[j][t][c]);
}
else{
int mid=lst[i]-lst[i-1]-1;
For(j,0,lst[i-1])For(t,0,n)if(n-lst[i-1]>=i-1-(lst[i-1]-j)&&dp[(i-1)&1][j][t][0]){
For(k,0,min(mid,i-1-(lst[i-1]-j))){
Add(dp[i&1][j+mid-k][j+mid-k][0],1ll*dp[(i-1)&1][j][t][0]*w[i-1]%Mod*C[mid][k]%Mod);
}
}
For(j,0,lst[i-1])For(t,0,n) if(n-lst[i-1]>=i-1-(lst[i-1]-j)&&dp[(i-1)&1][j][t][1]){
For(k,0,min(mid,i-1-(lst[i-1]-j))){
if(t<lst[i]-(j+mid-k))Add(dp[i&1][j+mid-k][j+mid-k][0],1ll*dp[(i-1)&1][j][t][1]*w[i-1]%Mod*C[mid][k]%Mod);
else Add(dp[i&1][j+mid-k][j+(mid-k)][0],1ll*dp[(i-1)&1][j][t][1]*C[mid][k]%Mod);
}
}
}
// For(j,0,lst[i])For(t,0,n)For(c,0,1) if(dp[i&1][j][t][c])cout<<i<<" "<<j<<" "<<t<<" "<<c<<" "<<dp[i&1][j][t][c]<<endl;
}
int ans=0;
For(t,0,n)For(c,0,1) ans+=dp[n&1][0][t][c],ans%=Mod;
return ans;
}