CCPC2020绵阳 B题 Building Blocks
Pro:
https://pintia.cn/problem-sets/1322796904464203776/problems/1322798545527595009
有一个用小方块搭成的立体图形
给出它的左前视图每一列的高度
然后钦定\(k\)个位置的方块数
求一共有多少种合法的方案
\(n,m,k<=1e5\)
Sol:
显然要考虑一个顺着左前序列的一列一列的DP
每一个高度限制会限制相邻的两列
也就是说每一列的方块会被两个限制限制
因此可以考虑\(dp[i][0/1]\)
表示当前已经放完了\(x+y<=i\)的所有方块
第\(x+y\)个限制0/1(是否被满足)的方案数
按照定义转移即可
#include<bits/stdc++.h>
#define N 220000
#define db double
#define ll long long
#define ldb long double
#define ull unsigned long long
using namespace std;
const int h=3,ki=149,mo=1e9+7;
inline int inc(int x,int k){x+=k;return x<mo?x:x-mo;}
inline int dec(int x,int k){x-=k;return x>=0?x:x+mo;}
inline int read()
{
char ch=0;int x=0,flag=1;
while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0',ch=getchar();}
return x*flag;
}
inline void write(int x)
{
if(!x)return (void)putchar(48);
if(x<0)putchar(45),x=-x;
int len=0,p[20];
while(x)p[++len]=x%10,x/=10;
for(int i=len;i>=1;i--)putchar(p[i]+48);
}
const db eps=1e-7,inf=1e9+7,pi=acos(-1);
inline db Read(){db x;scanf("%lf",&x);return x;}
inline void Write(db x){printf("%lf",x);}
int ksm(int x,int k)
{
int ans=1;
while(k){if(k&1)ans=1ll*ans*x%mo;k>>=1;x=1ll*x*x%mo;}
return ans;
}
int f(int n,int k){return dec(ksm(n,k),ksm(n-1,k));}
int g(int n,int k){return ksm(n,k);}
int p[N],cnt[N],lim[N],dp[N][2];
void work(int o)
{
int n=read(),m=read(),len=n+m,k=read();
for(int i=0;i<=len+1;i++)lim[i]=p[i]=cnt[i]=dp[i][0]=dp[i][1]=0;
for(int i=1;i<=len;i++)lim[i]=read();
for(int i=1;i<=len-1;i++)cnt[i+1]=min(min(n,m),min(i,len-i));
for(int i=1;i<=k;i++)
{
int x=read(),y=read(),t=read();cnt[x+y]--;
p[x+y]=max(p[x+y],t);p[x+y-1]=max(p[x+y-1],t);
}
for(int i=2;i<=len;i++)if(cnt[i]<0){printf("Case #%d: %d\n",o,0);return;}
for(int i=1;i<=len;i++)if(p[i]>lim[i]){printf("Case #%d: %d\n",o,0);return;}
if(p[1]<lim[1])dp[1][0]=1;else dp[1][1]=1;
for(int i=2;i<=len;i++)
{
int a=lim[i-1],b=lim[i];
if(p[i]<lim[i])
{
if(a==b)dp[i][1]=inc(dp[i][1],1ll*dp[i-1][0]*f(a,cnt[i])%mo);
if(a>=b)dp[i][1]=inc(dp[i][1],1ll*dp[i-1][1]*f(b,cnt[i])%mo);
if(a<b)dp[i][0]=inc(dp[i][0],1ll*dp[i-1][0]*f(a,cnt[i])%mo);
dp[i][0]=inc(dp[i][0],1ll*dp[i-1][1]*g(min(a,b-1),cnt[i])%mo);
}
else
{
if(a<=lim[i])dp[i][1]=inc(dp[i][1],1ll*dp[i-1][0]*f(a,cnt[i])%mo);
dp[i][1]=inc(dp[i][1],1ll*dp[i-1][1]*g(min(a,b),cnt[i])%mo);
dp[i][0]=0;
}
}
printf("Case #%d: %d\n",o,dp[len][1]);
}
int main()
{
int t=read();
for(int i=1;i<=t;i++)work(i);
return 0;
}