Loading

[AGC013D] Piling Up

题意

盲盒模球,每次拿出一个球,然后放入黑白球各一个,然后再拿一个。求最后拿出的球按顺序排列的序列个数。

Solution

考虑每一时刻黑白球的个数都不为负,所以考虑以黑球个数为横坐标,白球个数为纵坐标。这样我们对这里的操作进行一个转化:

  1. 先取一个白球,后取一个白球:相当于向斜右下对角线走一步;
  2. 先取一个白球,后取一个黑球:相当于不动;
  3. 先取一个黑球,后取一个白球:相当于不动;
  4. 先取一个黑球,后取一个黑球:相当于向斜左上对角线走一步。

考虑到 \(2\)\(3\) 是两种不同的方案,所以如果待在原地是有两种策略的。于是题意就转化成:在直线 \(x+y=n\) 的坐标大于等于 \(0\) 的整点上随机游走 \(m\) 步的方案数。

这个东西还能继续转化。就是考虑把步数当做横坐标,然后在这条直线上的点拉直作为纵坐标。这样就是问,从横坐标为 \(0\) 开始,每次横坐标 \(+1\),纵坐标 \(+1\)\(-1\) 或者不变,求走到最后 \(x=m\) 的方案数。注意,这里走的时候需要考虑题目中每一步是分开的。这里纵坐标的含义相当于黑球的个数,要时刻保证其非负。所以在情况 \(3,4\) 的时候也需要判断 \(j\not ={0}\)。同时在情况 \(1,2\) 的时候要保证 \(j\not ={n}\)

\(\color{red}\bigstar\) 去重的时候可以考虑在重复的路径中找一条特殊的来计数。

比如说这题,我们可以考虑用与 \(x\) 轴接触过的路径,然后记录它的纵坐标。即 \(f_{i,j}\) 表示走 \(i\) 步后,与 \(x\) 轴接触过的当前纵坐标为 \(j\) 的方案数。\(g_{i,j}\) 表示没有与 \(x\) 轴接触过,当前纵坐标是 \(j\) 的方案数。这样有:

\[f_{i,0}=f_{i-1,0}+f_{i-1,1}+g_{i-1,1}\\ f_{i,j}=f_{i-1,j}+f_{i-1,j-1}+(f_{i-1,j+1}+f_{i-1,j})[j\not ={n}]\\ g_{i,j}=g_{i-1,j}+g_{i-1,j-1}+(g_{i-1,j+1}+g_{i-1,j})[j\not ={n}] \]

注意当 \(j=1\) 时,采取第二种方式,会使得 \(g\to f\),需要特殊转移。

然后初始为 \(g_{0,1\sim n}=1,f_{0,0}=1\)。最后答案应该就是 \(f_{m,0\sim n}\)

Code

// Problem: 
//     AT_agc013_d D - Piling Up
//   
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/AT_agc013_d
// Memory Limit:  MB
// Time Limit: 256000 ms

#include<bits/stdc++.h>
#define ll long long
#define inf (1<<30)
#define INF (1ll<<60)
#define pii pair<int,int>
#define mkp make_pair
#define fi first
#define se second
#define all(a) a.begin(),a.end()
#define siz(a) (int)a.size()
#define pb emplace_back
#define rep(i,j,k) for(int i=(j);i<=(k);i++)
#define per(i,j,k) for(int i=(j);i>=(k);i--)
#define pt(a) cerr<<#a<<'='<<a<<' '
#define pts(a) cerr<<#a<<'='<<a<<'\n'
#define int long long
using namespace std;
const int MAXN=3010;
const int MOD=1e9+7;
int f[MAXN][MAXN],g[MAXN][MAXN];
void solve(){
	int n,m;cin>>n>>m;
	rep(i,1,n) g[0][i]=1;f[0][0]=1;
	rep(i,1,m){
		f[i][0]=(f[i-1][0]+f[i-1][1]+g[i-1][1])%MOD;
		rep(j,1,n){
			f[i][j]=(f[i-1][j]+f[i-1][j-1])%MOD;
			g[i][j]=(g[i-1][j]+g[i-1][j-1])%MOD;
			if(j!=n){
				f[i][j]=(f[i][j]+f[i-1][j+1]+f[i-1][j])%MOD;
				g[i][j]=(g[i][j]+g[i-1][j+1]+g[i-1][j])%MOD;
			}if(j==1){
				f[i][j]=(f[i][j]+g[i-1][j])%MOD;
				g[i][j]=(g[i][j]+MOD-g[i-1][j])%MOD;
			}
		}
	}
	int ans=0;
	rep(i,0,n) ans=(ans+f[m][i])%MOD;
	cout<<ans<<'\n';
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
//	int T;for(cin>>T;T--;)
		solve();
	return 0;
}
posted @ 2022-10-27 21:43  ZCETHAN  阅读(75)  评论(0编辑  收藏  举报