zoukankan      html  css  js  c++  java
  • Loj #2731 「JOISC 2016 Day 1」棋盘游戏

    Loj 2731 「JOISC 2016 Day 1」棋盘游戏

    JOI 君有一个棋盘,棋盘上有 (N)(3) 列 的格子。JOI 君有若干棋子,并想用它们来玩一个游戏。初始状态棋盘上至少有一个棋子,也至少有一个空位。

    游戏的目标是:在还没有放棋子的格子上依次放棋子,并填满整个棋盘。在某个格子上放置棋子必须满足以下条件之一:

    1. 这个格子的上下一格都放有棋子;
    2. 这个格子的左右一格都放有棋子。

    JOI 君想知道有多少种从初始状态开始,并达到游戏目标的方案,这个答案可能会非常大。请你帮 JOI 君算出这个答案,并对 (10^9+7) 取模。

    输入格式

    第一行有一个整数 (N) ,表示棋盘的大小为纵向 (3) 格,横向 (N) 格。

    接下来的三行均为仅由 ox 组成的字符串。这三行中第 (i) 行的第 (j) 个字符表示棋盘中从上到下第 (i) 行,从左到右第 (j) 个棋子的状态。其中 o 表示开始时有棋子被放置,x 表示开始时这个位置为没有放置着棋子。

    输出格式

    一个整数,表示符合条件的方案个数。

    样例输入 1

    3
    oxo
    xxo
    oxo
    

    样例输出 1

    14
    

    样例输入 2

    10
    ooxooxoxoo
    xooxxxoxxx
    oxoxoooooo
    

    样例输出 2

    149022720
    

    样例输入 3

    10
    ooxoxxoxoo
    oxxxxxoxxx
    oxooxoxoxo
    

    样例输出 3

    0
    

    样例解释 3

    没有可以达到最终状态的方案。

    样例输入 4

    20
    oxooxoxooxoxooxoxoxo
    oxxxoxoxxxooxxxxxoox
    oxooxoxooxooxooxoxoo
    

    样例输出 4

    228518545
    

    (JOI)(DP)题好恶心。

    显然,(1,3)行的空格左右两边必须是已经放好的棋子,否则无解。也就是说(1,3)行的空格可以再任意时刻放棋子。

    于是我们只需要对第(2)行中的空格进行(DP)就可以了。

    我们设(f_{i,j})表示((2,i))的空格在时刻(j)放了一个棋子,且((2,i-1))((2,i))之后放置的方案数;(g_{i,j})表示((2,i))的空格在时刻(j)放了一个棋子,且((2,i-1))((2,i))之前放置的方案数。

    我们的(f_{i,j},g_{i,j})都是没有考虑((1,i))以及((3,i))的放置情况的,当我们转移(f_{i+1,j},g_{i+1,j})的时候我们再考虑。因为如果((2,i-1),(2,i+1))都在((2,i))之前放置,则((1,i),(3,i))可以任意放置,否则必须在((2,i))之前放置。

    转移就按((2,i))((2,i+1))(4)中情况讨论。

    细节就不说了,讨论就行了。

    转移的时候还要用前缀和优化。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define pr pair<int,int>
    #define mp(a,b) make_pair(a,b)
    #define N 2005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    const ll mod=1e9+7;
    ll ksm(ll t,ll x) {
    	ll ans=1;
    	for(;x;x>>=1,t=t*t%mod)
    		if(x&1) ans=ans*t%mod;
    	return ans;
    }
    int n;
    char mp[4][N];
    ll fac[N*3],ifac[N*3];
    ll C(int n,int m) {
    	if(n<m) return 0;
    	return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    int u[N];
    ll f[N][N*3],g[N][N*3];
    int res,sum[N];
    ll pre[N*3];
    int main() {
    	n=Get();
    	fac[0]=1;
    	for(int i=1;i<=3*n;i++) fac[i]=fac[i-1]*i%mod;
    	ifac[3*n]=ksm(fac[3*n],mod-2);
    	for(int i=3*n-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
    	for(int i=1;i<=3;i++) {
    		scanf("%s",mp[i]+1);
    	}
    	
    	for(int i=1;i<=n;i++) {
    		if(mp[1][i]=='x'&&(mp[1][i-1]!='o'||mp[1][i+1]!='o')) {cout<<0;return 0;}
    		if(mp[3][i]=='x'&&(mp[3][i-1]!='o'||mp[3][i+1]!='o')) {cout<<0;return 0;}
    	}
    	
    	for(int i=1;i<=n;i++) {
    		if(mp[1][i]=='x') u[i]++;
    		if(mp[3][i]=='x') u[i]++;
    	}
    	for(int i=1;i<=n;i++) sum[i]=sum[i-1]+u[i]+(mp[2][i]=='x');
    	
    	
    	if(mp[2][1]=='x') f[1][1]=1;
    	else f[1][0]=1;
    	for(int i=2;i<=n;i++) {
    		if(mp[2][i]=='x') {
    			if(mp[2][i-1]=='x') {
    				memset(pre,0,sizeof(pre));
    				for(int j=1;j<=sum[i-1];j++) {//f,i-1由上下贡献 
    					if(u[i-1]==2) pre[j]=(pre[j-1]+f[i-1][j]*j%mod*(j+1))%mod;
    					else if(u[i-1]==1) pre[j]=(pre[j-1]+f[i-1][j]*j)%mod;
    					else pre[j]=(pre[j-1]+f[i-1][j])%mod;
    				}
    				
    				for(int j=sum[i-1];j>=1;j--) if(j>u[i-1]) pre[j]=pre[j-u[i-1]];
    				for(int j=1;j<=u[i-1];j++) pre[j]=0;
    				
    				for(int j=1;j<=sum[i-1];j++) (f[i][j]+=pre[sum[i-1]]-pre[j-1]+mod)%=mod;
    				for(int j=2;j<=sum[i-1]+1;j++) (g[i][j]+=pre[j-1])%=mod;
    				
    				memset(pre,0,sizeof(pre));
    				for(int j=1;j<=sum[i-1];j++) {//g,i-1由上下贡献 
    					if(u[i-1]==2) pre[j]=(pre[j-1]+g[i-1][j]*j%mod*(j+1))%mod;
    					else if(u[i-1]==1) pre[j]=(pre[j-1]+g[i-1][j]*j)%mod;
    					else pre[j]=(pre[j-1]+g[i-1][j])%mod;
    				}
    				
    				for(int j=sum[i-1];j>=1;j--) if(j>u[i-1]) pre[j]=pre[j-u[i-1]];
    				for(int j=1;j<=u[i-1];j++) pre[j]=0;
    				for(int j=2;j<=sum[i-1]+1;j++) (g[i][j]+=pre[j-1])%=mod;
    				
    				memset(pre,0,sizeof(pre));
    				for(int j=1;j<=sum[i-1];j++) {//g,i-1由左右贡献 
    					(pre[j]+=pre[j-1])%=mod;
    					if(!u[i-1]) {
    						(pre[j]+=g[i-1][j])%=mod;
    					} else if(u[i-1]==1) {
    						(pre[j+1]+=g[i-1][j]*j)%=mod;
    						(pre[j]+=g[i-1][j]*(sum[i-1]-j))%=mod;
    					} else {
    						(pre[j]+=g[i-1][j]*(sum[i-1]-j-1)%mod*(sum[i-1]-j))%=mod;
    						(pre[j+1]+=g[i-1][j]*j%mod*(sum[i-1]-j-1)%mod*2)%=mod;
    						(pre[j+2]+=g[i-1][j]*j%mod*(j+1))%=mod;
    					}
    				}
    				for(int j=1;j<=sum[i-1];j++) (f[i][j]+=pre[sum[i-1]]-pre[j-1]+mod)%=mod;
    			} else {
    				for(int j=1;j<=sum[i-1]+1;j++) {
    					if(u[i-1]==0) g[i][j]=f[i-1][0];
    					else if(u[i-1]==1) g[i][j]=f[i-1][0]*sum[i-1]%mod;
    					else g[i][j]=f[i-1][0]*(sum[i-1]-1)%mod*sum[i-1]%mod;
    				}
    			}
    		} else {
    			if(mp[2][i-1]=='x') {
    				for(int j=1;j<=sum[i-1];j++) {
    					if(u[i-1]==0) {
    						(f[i][0]+=f[i-1][j]+g[i-1][j])%=mod;
    					} else if(u[i-1]==1) {
    						(f[i][0]+=f[i-1][j]*j+g[i-1][j]*(sum[i-1]))%=mod;
    					} else {
    						(f[i][0]+=f[i-1][j]*j%mod*(j+1)+g[i-1][j]*(sum[i-1])%mod*(sum[i-1]-1))%=mod;
    					}
    				}
    			} else {
    				if(u[i-1]==0) f[i][0]=f[i-1][0];
    				else if(u[i-1]==1) f[i][0]=f[i-1][0]*sum[i-1]%mod;
    				else f[i][0]=f[i-1][0]*(sum[i-1]-1)%mod*sum[i-1]%mod;
    			}
    		}
    	}
    	ll ans=0;
    	if(mp[2][n]=='o') {
    		if(!u[n]) (ans+=(f[n][0]))%=mod;
    		else if(u[n]==1) (ans+=f[n][0]*sum[n])%=mod;
    		else (ans+=f[n][0]*(sum[n]-1)%mod*sum[n])%=mod;
    	} else {
    		for(int i=1;i<=sum[n];i++) {
    			if(!u[n]) (ans+=(f[n][i]+g[n][i]))%=mod;
    			else if(u[n]==1) (ans+=f[n][i]*i+g[n][i]*sum[n])%=mod;
    			else (ans+=f[n][i]*i%mod*(i-1)+g[n][i]*sum[n]%mod*(sum[n]-1))%=mod;
    		}
    	}
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    JSP 072: 处理注册结果样式的显示
    JSP 07: 开发注册页面
    JSP 06: 两个内置对象request和response
    Java Web 01: 什么是http协议
    JSP 05: JSP定义表达式和内容输出表达式
    JSP 04: 如何在JSP页面中书写Java代码
    JSP 03: 创建一个JSP页面并启动运行项目
    Fail 02: Port 8080 required by Tomcat Server at localhost is already in use.
    Fail 03: netstat 不是内部或外部命令
    Build 01: 安装新的JDK
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10596270.html
Copyright © 2011-2022 走看看