zoukankan      html  css  js  c++  java
  • [CSP-S模拟测试]:题(DP+数学)

    题目描述

    出个题就好了.这就是出题人没有写题目背景的原因。
    你在平面直角坐标系上。
    你一开始位于$(0,0)$。
    每次可以在上/下/左/右四个方向中选一个走一步。
    即:从$(x,y)$走到$(x,y+1),(x,y-1),(x-1,y),(x+1,y)$四个位置中的其中一个。
    允许你走的步数已经确定为$n$,现在你想走$n$步之后回到$(0,0)$。
    但这太简单了,你希望知道有多少种不同的方案能够使你在n步之后回到$(0,0)$,当且仅当两种方案至少有一步走的方向不同,这两种方案被认为是不同的.
    答案可能很大所以只需要输出答案对${10}^9+7$取模后的结果。
    这还是太简单了,所以你给能够到达的格点加上了一些限制,一共有三种限制,加上没有限制的情况,一共有四种情况,用$0,1,2,3$标号:
    $0.$没有任何限制,可以到达坐标系上所有的点。即能到达的点集为${ (x,y)|x,y$为整数$}$
    $1.$只允许到达x轴非负半轴上的点。即能到达的点集为${ (x,y)|x$为非负数$,y=0}$
    $2.$只允许到达坐标轴上的点。即能到达的点集为${ (x,y)|x=0$或$y=0}$
    $3.$只允许到达$x$轴非负半轴上的点,$y$轴非负半轴上的点以及第$1$象限的点。即能到达的点集为${ (x,y)| xgeqslant 0,ygeqslant 0}$


    输入格式

    一行两个整数(空格隔开)n和typ,分别表示你必须恰好走的步数和限制的种类。
    typ的含义见【题目描述】


    输出格式

    一行一个整数ans,表示不同的方案数对${10}^9+7$取模后的结果。


    样例

    样例输入0:
    100 0
    样例输出0:
    383726909
    样例输入1:
    100 1
    样例输出1:
    265470434
    样例输入2:
    100 2
    样例输出2:
    376611634
    样例输入3:
    100 3
    样例输出3:
    627595255


    数据范围与提示

    $10\%$的数据,$typ=0,nleqslant 100$
    $10\%$的数据,$typ=0,nleqslant 1,000$
    $ 5\%$的数据,$typ=0,nleqslant 100,000$
    $10\%$的数据,$typ=1,nleqslant 100$
    $10\%$的数据,$typ=1,nleqslant 1,000$
    $ 5\%$的数据,$typ=1,nleqslant 100,000$
    $10\%$的数据,$typ=2,nleqslant 100$
    $15\%$的数据,$typ=2,nleqslant 1,000$
    $10\%$的数据,$typ=3,nleqslant 100$
    $10\%$的数据,$typ=3,nleqslant 1,000$
    $ 5\%$的数据,$typ=3,nleqslant 100,000$
    以上$11$部分数据没有交集。
    $100%$的数据,保证$n$为偶数,$2leqslant nleqslant 100,000$,$0leqslant typleqslant 3$。


    题解

    一个数学和$DP$的大结合。

    首先,这四问都可以用$Theta (n^3)$的$DP$拿到部分分。

    定义$dp[t][i][j]$表示$t$时刻在点$(i,j)$的方案数。

    $DP$式子为:

    $dp[t][i][j]=dp[t-1][i-1][j]+dp[t-1][i][j-1]+dp[t-1][i+1][j]+dp[t-1][i][j+1]$。

    注意边界就好了。

    期望得分:$40$分。

    $typ=0$的情况,显然让我们想到了visit那道题,25分就轻松拿到了。

    $typ=1$的情况,我们可以理解为向右走为进栈,想左走为出栈,那么就是求卡特兰数的第$frac{n}{2}$项,直接用公式解决就可以了,附带一个卡特兰数的求法

    $typ=2$的情况,注意数据范围$nleqslant 1,000$,所以我们可以考虑$Theta (n^2)$的做法,定义$dp[t][i]$表示在$t$时刻位于距离原点为$i$的方案数,现在我们只考虑它在$x$轴上的情况,那么$DP$式子为:$dp[t][i]=dp[t-1][i-1]+dp[t-1][i+1]$,现在放回在坐标系上的情况,那么只有在原点的时候才会有四个方向向它贡献答案,那么$DP$式子只在$i=0$时发生改变,为:$dp[t][0]=4 imes dp[t-1][1]$,也可以用滚动数组节省空间。注:正解为卡特兰数,在此介绍另一种做法。

    $typ=3$的情况,只是在$typ=1$的情况上加一个枚举横向走的步数$i$纵向的步数即为$n-i$,需要注意的是横向的步数肯定为偶数步,那么方案数就是:$C_n^i imes catalanfrac{i}{2} imes catalanfrac{n-i}{2}$。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,typ;
    long long inv[200001],jget_C[200001];
    long long dp[1001][1001];
    long long qpow(long long x,long long y)
    {
    	long long res=1;
    	while(y)
    	{
    		if(y%2)res=(res*x)%1000000007;
    		y>>=1;
    		x=(x*x)%1000000007;
    	}
    	return res;
    }
    void pre_work()
    {
    	jget_C[0]=1; jget_C[1]=1;
    	for(int i=2;i<=n;i++)jget_C[i]=1LL*jget_C[i-1]*i%1000000007;
    	inv[0]=1; inv[1]=1;
    	for(int i=2;i<=n;i++)inv[i]=1LL*(1000000007-1000000007/i)*inv[1000000007%i]%1000000007;
    	for(int i=1;i<=n;i++)inv[i]=1LL*inv[i]*inv[i-1]%1000000007;
    }
    long long get_C(int n,int m)
    {
    	if(n<m)return 0;
    	if(m==0)return 1;
    	return (jget_C[n]%1000000007*inv[m]%1000000007*inv[n-m]%1000000007)%1000000007;
    }
    long long get_Catalan(int x){return get_C(2*x,x)%1000000007*qpow((long long)(x+1),1000000005)%1000000007;}
    int main()
    {
    	scanf("%d%d",&n,&typ);
    	pre_work();
    	switch(typ)
    	{
    		case 0:
    		{
    			long long ans=0; 
    			for(int i=0;i<=n;i+=2)
    				ans=(ans+get_C(n,i)%1000000007*get_C(i,i/2)%1000000007*get_C(n-i,(n-i)/2)%1000000007)%1000000007;
    			printf("%lld",ans%1000000007);
    			break;
    		}
    		case 1:
    		{
    			printf("%lld",get_Catalan(n/2));
    			break;
    		}
    		case 2:
    		{
    			dp[0][0]=1;
    			for(int i=1;i<=n;i++)
    			{
    				dp[i][0]=dp[i-1][1]*4%1000000007;
    				for(int j=1;j<=n/2;j++)
    				dp[i][j]=(dp[i-1][j-1]+dp[i-1][j+1])%1000000007;
    			}
    			printf("%lld
    ",dp[n][0]);
    			break;
    		}
    		case 3:
    		{
    			long long ans=0;
    			for(int i=0;i<=n;i+=2)
    				ans=(ans+get_C(n,i)%1000000007*get_Catalan(i/2)%1000000007*get_Catalan((n-i)/2)%1000000007)%1000000007;
    			printf("%lld",ans);
    		   	break;
    		}
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    第二阶段冲刺01
    第十三周进度条
    构建之法阅读笔记5
    水王2
    购买一批书的最低价格
    第十二周进度条
    个人工作总结08
    个人工作总结07
    人机交互设计分析之搜狗输入法
    第八周的学习进度条
  • 原文地址:https://www.cnblogs.com/wzc521/p/11254533.html
Copyright © 2011-2022 走看看