• loj 3157 [NOI2019]机器人


    loj 3157 [NOI2019]机器人

    https://loj.ac/problem/3157

    NOEqln.png

    NOEOO0.png

    NOELyq.png

    Tutorial

    https://blog.csdn.net/WAautomaton/article/details/96825203

    http://yyy.is-programmer.com/posts/202122.html

    https://www.cnblogs.com/suncongbo/p/11217236.html

    https://www.cnblogs.com/Tiw-Air-OAO/p/13070992.html

    考虑设 (dp(l,r,k)) 表示区间 ([l,r]) 中高度最大的柱子的高度为 (k) .

    考虑枚举高度最大的柱子的位置 (k) ,需要满足 (|(k-l)-(r-k)| le 2) .

    [dp(l,r,k)=sum_k(sum_{x le k} dp(l,k-1,x))(sum_{x<k}dp(k+1,r,x)) ]

    由于(k)对于位置的需求,所以需要计算的区间在(n=300)时只有(m=2220)个左右.

    考虑若对于所有柱子有 (A_i=1,B_i=10^9) ,那么 (dp(l,l,k)=1) ,则它的前缀和可以看作关于 (k) 的一次函数,那么从上面的表达式可以看出, (dp(l,r,k))的前缀和就是关于(k)(r-l+1)次多项式.

    回到一般情况,此时的(dp(l,r,k))是一个分段函数,我们可以根据(A_i,B_i+1)将高度分为若干段,满足每一段对于每个柱子的合法性不变.设当前段为([L,R)),此时可以将(dp(l,r,k))看作关于(k-L)的函数,而常数项则是(dp(l,r,L-1)).

    那么我们DP维护点值,利用拉格朗日插值进行转移即可.计算一段的时间复杂度为 (O(mn^2)) .总复杂度 (O(mn^3)) .但是由于常数很优秀,所以可以通过

    Code

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define debug(...) fprintf(stderr,__VA_ARGS__)
    #define inver(a) power(a,mod-2)
    using namespace std;
    inline char gc() {
    	static char buf[100000],*l=buf,*r=buf;
    	return l==r&&(r=(l=buf)+fread(buf,1,100000,stdin),l==r)?EOF:*l++;
    }
    template<class T> void rd(T &x) {
    	x=0; int f=1,ch=gc();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    	while(ch>='0'&&ch<='9'){x=x*10-'0'+ch;ch=gc();}
    	x*=f;
    }
    typedef long long ll;
    const int mod=1e9+7;
    const int maxn=300+5,maxm=2300;
    const int maxp=maxn<<1;
    int n,A[maxn],B[maxn];
    int fac[maxn],inv[maxn];
    int p,H[maxp];
    int ncnt,id[maxn][maxn];
    int c[maxm],good[maxn];
    int dp[maxm][maxn],cnt[maxm],deg[maxm],vis[maxm];
    inline int add(int x) {return x>=mod?x-mod:x;}
    inline int sub(int x) {return x<0?x+mod:x;}
    ll power(ll x,ll y) {
    	ll re=1;
    	while(y) {
    		if(y&1) re=re*x%mod;
    		x=x*x%mod;
    		y>>=1;
    	}
    	return re;
    }
    int cal(int n,int x,int *y) {
    	static int pre[maxn],suf[maxn];
    	pre[0]=x;
    	for(int i=1;i<=n;++i) pre[i]=(ll)pre[i-1]*sub(x-i)%mod;
    	suf[n]=sub(x-n);
    	for(int i=n-1;i>=0;--i) suf[i]=(ll)suf[i+1]*sub(x-i)%mod;
    	int re=0;
    	for(int i=0;i<=n;++i) {
    		int d=(ll)((n-i)&1?mod-1:1)*inv[n-i]%mod*inv[i]%mod;
    		if(i!=0) d=(ll)d*pre[i-1]%mod;
    		if(i!=n) d=(ll)d*suf[i+1]%mod;
    		re=(re+(ll)d*y[i])%mod;
    	}
    	return re;
    }
    void extend(int u,int d) {
    	while(cnt[u]<d) {
    		++cnt[u];
    		dp[u][cnt[u]]=cal(deg[u],cnt[u],dp[u]);
    	}
    }
    void dfs_init(int l,int r) {
    	if(id[l][r]!=-1) return;
    	if(l>r) {id[l][r]=0; return;}
    	id[l][r]=++ncnt;
    	for(int k=l;k<=r;++k) if(abs((k-l)-(r-k))<=2) {
    		dfs_init(l,k-1),dfs_init(k+1,r);
    	}
    }
    int dfs(int l,int r) {
    	int u=id[l][r]; if(vis[u]) return u; vis[u]=1;
    	cnt[u]=deg[u]=0;
    	for(int k=l;k<=r;++k) if(abs((k-l)-(r-k))<=2) {
    		int L=dfs(l,k-1),R=dfs(k+1,r); if(!good[k]) continue;
    		int d=max(deg[u],deg[L]+deg[R]);
    		extend(L,d+1),extend(R,d),extend(u,d);
    		for(int i=0;i<=d;++i) dp[u][i]=(dp[u][i]+(ll)dp[L][i+1]*dp[R][i])%mod;
    		deg[u]=d;
    	}
    	if(deg[u]==0&&dp[u][0]==0) dp[u][0]=c[u];
    	else {
    		for(int i=deg[u];i>=0;--i) dp[u][i+1]=dp[u][i];
    		dp[u][0]=c[u],++deg[u],++cnt[u];
    		for(int i=1;i<=deg[u];++i) dp[u][i]=add(dp[u][i]+dp[u][i-1]);
    	}
    	return u;
    }
    void init(int n) {
    	fac[0]=1;
    	for(int i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%mod;
    	inv[n]=inver(fac[n]);
    	for(int i=n;i>=1;--i) inv[i-1]=(ll)inv[i]*i%mod;
    }
    int main() {
    	freopen("robot.in","r",stdin);
    	freopen("robot.out","w",stdout);
    	rd(n);
    	init(n);
    	for(int i=1;i<=n;++i) {
    		rd(A[i]),rd(B[i]),++B[i];
    		H[++p]=A[i],H[++p]=B[i];
    	}
    	sort(H+1,H+p+1),p=unique(H+1,H+p+1)-H-1;
    	for(int i=1;i<=n;++i) {
    		A[i]=lower_bound(H+1,H+p+1,A[i])-H;
    		B[i]=lower_bound(H+1,H+p+1,B[i])-H;
    	}
    	memset(id,-1,sizeof(id));
    	dfs_init(1,n),c[0]=1;
    	for(int i=1;i<p;++i) {
    		for(int j=1;j<=n;++j) good[j]=A[j]<=i&&i<B[j];
    		dfs(1,n);
    		for(int j=1;j<=ncnt;++j) {
    			vis[j]=0;
    			c[j]=cal(deg[j],H[i+1]-H[i],dp[j]);
    			for(int k=0;k<=cnt[j];++k) dp[j][k]=0;
    		}
    	}
    	printf("%d
    ",c[1]);
    	return 0;
    } 
    
  • 相关阅读:
    LInux SSH远程文件/目录传输命令scp(转载)
    Linux系统时间设置(转载)
    Linux重置mysql密码(转载)
    快速输入(简单版)
    bitset
    或 、与、异或
    bitset
    Java面向对象3(K~O)
    Java面向对象2(G~J)
    数据结构实验之栈与队列六:下一较大值(二)(SDUT 3333)
  • 原文地址:https://www.cnblogs.com/ljzalc1022/p/13228818.html
Copyright © 2020-2023  润新知