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
",o,0);return;}
	for(int i=1;i<=len;i++)if(p[i]>lim[i]){printf("Case #%d: %d
",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
",o,dp[len][1]);
}
int main()
{
	int t=read();
	for(int i=1;i<=t;i++)work(i);
	return 0;
}
原文地址:https://www.cnblogs.com/Creed-qwq/p/13931125.html