嘟嘟嘟




这道题dp虽然不难,但是我还是没推出来,感觉最近脑子不太好用啊。

于是就跑去问神仙gjx(全国前三!)了。(外出集训真是好)




神仙不愧是神仙,一会儿就想出来了,而且方法还比网上的题解好懂。

dp[i][j]表示用值域为[1, i]的数,凑出的所有合法序列的值的和。

然后规定序列必须是严格递增的,这样答案再乘以一个\(n!\)就行了。

转移的时候,我们考虑\(i\)这个数用不用上,于是有:\(dp[i][j] = dp[i - 1][j] +i * dp[i - 1][j - 1]\)。现在感觉这个挺好理解的,如果用上\(i\)了,\(i\)就必须放在最后面,并且答案要乘以\(i\)。

但这个复杂度\(O(nA)\)的,\(A\)太大不好办。

然后gjx大佬告诉我,这个dp式是一个关于\(j\)的\(2n\)次多项式,然后给我证了一下,但还是不太懂:

首先知道\(dp[i][1] = \frac{i * (i + 1)}{2}\),猜想这可能是一个\(2n\)次的。

然后把转移方程中的\(dp[i - 1][j]\)不断展开,得到了\(dp[i][j] = \sum _ {k = 0} ^ {i - 1} dp[k][j] *(k + 1)\)。于是发现,这是一个关于\(j\)的\(2n\)次多项式。

(感觉自己还是不太理解)




这篇题解的证明好像也不错, 应该是数学归纳法,我得学一下)




知道这是个多项式,就可以拉格朗日差值了。

注意dp的边界取值,我这里debug了好久。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define In inline
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-8;
const int maxn = 505;
inline ll read()
{
ll ans = 0;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) last = ch, ch = getchar();
while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < 0) x = -x, putchar('-');
if(x >= 10) write(x / 10);
putchar(x % 10 + '0');
} int A, n, mod;
ll fac[maxn << 1], dp[maxn << 1][maxn]; In ll quickpow(ll a, ll b)
{
ll ret = 1;
for(; b; b >>= 1, a = a * a % mod)
if(b & 1) ret = ret * a % mod;
return ret;
} ll inv[maxn << 1], pre[maxn << 1], suf[maxn << 1];
In ll calc(int n)
{
inv[n] = quickpow(fac[n], mod - 2);
for(int i = n - 1; i >= 0; --i) inv[i] = inv[i + 1] * (i + 1) % mod;
pre[0] = A;
for(int i = 1; i <= n; ++i) pre[i] = pre[i - 1] * (A - i) % mod;
suf[n + 1] = 1;
for(int i = n; i >= 0; --i) suf[i] = suf[i + 1] * (A - i) % mod;
ll ret = 0;
for(int i = 0; i <= n; ++i)
{
ll tp = (i - 1 < 0 ? 1 : pre[i - 1]) * suf[i + 1] % mod * inv[i] % mod * inv[n - i] % mod;
if((n - i) & 1) tp = -tp;
ret = (ret + dp[i][n >> 1] * tp % mod + mod) % mod;
}
return ret;
} int main()
{
A = read(), n = read(), mod = read();
fac[1] = 1;
for(int i = 2; i <= (n << 1); ++i) fac[i] = fac[i - 1] * i % mod;
dp[0][0] = 1;
for(int i = 1; i <= (n << 1); ++i)
{
dp[i][1] = i * (i + 1) / 2;
dp[i][i] = fac[i];
for(int j = 2; j < i; ++j)
dp[i][j] = (dp[i - 1][j] + dp[i - 1][j - 1] * i % mod) % mod;
}
if(A <= (n << 1)) write(dp[A][n] * fac[n] % mod), enter;
else write(calc(n << 1) * fac[n] % mod), enter;
return 0;
}

[国家集训队] calc的更多相关文章

  1. [国家集训队] calc(动规+拉格朗日插值法)

    题目 P4463 [国家集训队] calc 集训队的题目真是做不动呀\(\%>\_<\%\) 朴素方程 设\(f_{i,j}\)为前\(i\)个数值域\([1,j]\),且序列递增的总贡献 ...

  2. P4463 [国家集训队] calc(拉格朗日插值)

    传送门 设\(dp[i][j]\)为考虑\(i\)个数,其中最大值不超过\(j\)的答案,那么转移为\[dp[i][j]=dp[i-1][j-1]\times i\times j+dp[i][j-1] ...

  3. Luogu P4463 [国家集训队] calc

    WJMZBMR的题果然放在几年后看来仍然挺神,提出了一种独特的优化DP的方式 首先我们想一个暴力DP,先定下所有数的顺序(比如强制它递增),然后最后乘上\(n!\)种排列方式就是答案了 那么我们容易想 ...

  4. p4463 [国家集训队] calc

    分析 代码 #include<bits/stdc++.h> using namespace std; ][],Ans; inline int pw(int x,int p){ ; whil ...

  5. BZOJ 2038: [2009国家集训队]小Z的袜子(hose)

    2038: [2009国家集训队]小Z的袜子(hose) Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 7676  Solved: 3509[Subm ...

  6. bzoj2152 / P2634 [国家集训队]聪聪可可(点分治)

    P2634 [国家集训队]聪聪可可 淀粉质点分治板子 边权直接 mod 3 直接点分治统计出所有的符合条件的点对再和总方案数约分 至于约分.....gcd搞搞就好辣 #include<iostr ...

  7. [洛谷P1527] [国家集训队]矩阵乘法

    洛谷题目链接:[国家集训队]矩阵乘法 题目背景 原 <补丁VS错误>请前往P2761 题目描述 给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数. 输入输出格式 输入 ...

  8. P4827「国家集训队」 Crash 的文明世界

    「国家集训队」 Crash 的文明世界 提供一种不需要脑子的方法. 其实是看洛谷讨论版看出来的( (但是全网也就这一篇这个方法的题解了) 首先这是一个关于树上路径的问题,我们可以无脑上点分治. 考虑当 ...

  9. BZOJ 2039: [2009国家集训队]employ人员雇佣

    2039: [2009国家集训队]employ人员雇佣 Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 1369  Solved: 667[Submit ...

随机推荐

  1. datatable删除行之datatable.Rows[i].Delete()。标记之后行没有了

    使用Delete()之后行消失了 先在for循环外加上dt.AcceptChanges(); 删除时在dt.AcceptChanges();

  2. Receiver 和 Direct方式的区别

    Kafka direct 跟receiver 方式接收数据的区别? Receiver是使用Kafka的高层次Consumer API来实现的.Receiver从Kafka中获取的数据都是存储在Spar ...

  3. makefile中":=","=","?=","+="

    = 无关位置的等于,值永远等于最后的值 比如: x =a y =$(x) x =b 那么y的值永远等于最后的值,等于 b ,而不是a        := 有关位置的等于,值取决于当时位置的值 比如: ...

  4. 使用Java打印字符串表格(中英文内容不乱)

    最近在学习使用java来编写cli应用,但是在信息展示上碰到了难题.原因是没有很好工具来展示一个由字符串组成的表格.在git上搜到阿里巴巴有一个叫做 text-ui 的开源项目可以用,但是这个工具在制 ...

  5. 微信服务号获取openid方法

    public function tetst(){ if(!isset($_GET['code'])){ $APPID = $this->app_id; $ran = rand(1,100); / ...

  6. 正则表达式+XML+反射+设计模式作业

    正则表达式+XML+反射+设计模式作业 一.    填空题 Class.forName('com.bjsxt.stumgr.entity.Student').newInstance( ); 语句的作用 ...

  7. 《.NET之美》之程序集

    一.什么是程序集(Assembly)? 经由编译器编译得到的,供CLR进一步编译执行的那个中间产物,在WINDOWS系统中,它一般表现为·dll或者是·exe的格式,但是要注意,它们跟普通意义上的WI ...

  8. Python 中 and 和 or 的短路原则

    对于 and 来说: 如果第一个条件的结论为假,那么 and 前后两个条件组成的表达式计算结果一定为假,后面的条件计算机不会进行计算 对于 or 来说: 如果第一个条件的结论为真,那么 or 前后两个 ...

  9. 【代码笔记】Web--使用Chrome来查看网页源代码

    一,用Chrome打开百度页面,如图所示. 二,鼠标右键--->显示网页源代码--->如图所示. 三,鼠标右键--->检查---->如图所示.此时可以通过Device来看不同设 ...

  10. Windows下使用Rtools编译R语言包

    使用devtools安装github中的R源代码时,经常会出各种错误,索性搜了一下怎么在Windows下直接打包,网上的资料也是参差不齐,以下是自己验证通过的. 一.下载Rtools 下载地址:htt ...