zoukankan      html  css  js  c++  java
  • AGC024E Sequence Growing Hard

    题意

    给出(n),(m),(mu),问有多少个序列组((A_0,A_1,dots,A_n))满足:

    • 序列(Ai)的长度恰好为(i)
    • 所有元素均在([1,m])
    • (A_{i−1})(A_i)的子序列
    • (A_i)的字典序大于(A_{i−1})

    答案模(mu)输出。
    (n,k le 300)
    传送门

    思路

    又是一道神仙(dp)
    一个很重要的思路:把数从小往大插入
    当我们插入(i)时,因为数列中的数都是(le i)的,所以(i)插在所有位置都是可以的
    例如:(1323),考虑插入(3)
    最前面:(31323);一:(13323);二:(13323);三:(13233);四:(13233)
    不过同时我们也发现:会算重。而且是当插到(i)前面的时候
    所以我们强行规定相同数一定要插在后面就可以了。
    我们记录(dp[i][j][k])表示当前进行到第(i)个操作,放到数字(j),有(k)个数后可以放(注意这意味着有(k+1)种,因为开头也是可以放的)。
    转移:

    • (dp[i][j][k - 1]+= dp[i][j][k] (k>0))表示这个位置的数后不放
    • (dp[i][j + 1][i] += dp[i][j][k] (k=0))(j)已经不能放了,从(j+1)新开始放(不存在相同的,所以所有数后都能放)
    • (dp[i + 1][j][k] += dp[i][j][k]*(k + 1)) 表示我们放置这个数,放这个数有(k+1)中选择。

    代码十分简短
    参考

    #include <bits/stdc++.h>
    #define upd(x,y) x=(x+y>=mu?x+y-mu:x+y)
    int n,m,mu,dp[305][305][305];
    int main(){
    	scanf("%d%d%d",&n,&m,&mu);
    	dp[0][1][0]=1;
    	for (int i=0;i<=n;i++)
    		for (int j=1;j<=m;j++)
    			for (int k=i;k>=0;k--){
    				if (k) upd(dp[i][j][k-1],dp[i][j][k]);
    				else upd(dp[i][j+1][i],dp[i][j][k]);
    				upd(dp[i+1][j][k],1ll*dp[i][j][k]*(k+1)%mu);
    			} 
    	printf("%d",dp[n][m][0]);
    }
    
    * 生而自由 爱而无畏 *
  • 相关阅读:
    韩式英语
    Daily dictation 听课笔记
    words with same pronunciation
    you will need to restart eclipse for the changes to take effect. would you like to restart now?
    glottal stop(britain fountain mountain)
    education 的发音
    第一次用Matlab 的lamada语句
    SVN的switch命令
    String的split
    SVN模型仓库中的资源从一个地方移动到另一个地方的办法(很久才解决)
  • 原文地址:https://www.cnblogs.com/flyfeather6/p/11778415.html
Copyright © 2011-2022 走看看