@description@

现有不等式组:

\[\begin{cases}
x_1 + x_2 + \dots + x_m \leq s\\
x_i \leq t &1 \leq i \leq n
\end{cases}
\]

求该不等式组的正整数解个数。

原题传送门。

@accepted code@

发现这道题就 \(m - n \leq 100\) 可以利用,其他数据范围都太大了。

如果 m = n,由于还有条件 \(nt \leq s\),所以答案 = \(n^t\)。

如果 m = n + 1,假设前 n 个数之和为 p,则最后 1 个数对答案的贡献为 (s-p-1)。

可以拆成 (s-1) 与 (-p),前者实际上就是 \((s-1)\times n^t\);而后者如果考虑每一个变量的贡献为 \(-x_i\),总贡献即 \(-p\),推一下式子即可。

进一步地,不妨猜想假如前 n 个数之和为 p,则后 n - m 个数对答案的贡献是关于 p 的 n - m 次多项式。

事实上,后 n - m 个数的贡献就是 \({s - p\choose n - m}\)(比较显然)。由此也可以看出的确是关于 p 的 n - m 次多项式。

我们暴力 \(O((n - m)^2)\) 展开该多项式得到 \(\sum_{i=0}^{n-m}a_ip^i\)。

接下来如果算出 \(f_i = \sum_{1\leq x_1, x_2, \dots, x_n\leq t}(x_1 + x_2 + \dots + x_n)^i\),最后答案就是 \(ans = \sum a_if_i\)。

记 \(F(x) = \sum_{i=0}\frac{\sum_{j=1}^{t}j^i}{i!}x^i\),则 \(f_i = i!\times [x^i]F^n(x)\)。

自然数幂和(使用斯特林数即可)算出 \(F(x)\) 前 m - n 项,再快速幂算 \(F^n(x)\)。多项式乘法直接 \(O((m-n)^2)\) 算。

因此总时间复杂度 \(O((m-n)^2\log n)\)。

@accepted code@

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. typedef long long ll;
  5. const int MAXN = 105;
  6. const int MOD = 1000000007;
  7. inline int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
  8. inline int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
  9. inline int mul(int x, int y) {return 1LL * x * y % MOD;}
  10. int pow_mod(int b, int p) {
  11. int ret = 1;
  12. for(int i=p;i;i>>=1,b=mul(b,b))
  13. if( i & 1 ) ret = mul(ret, b);
  14. return ret;
  15. }
  16. int fct[MAXN + 5], ifct[MAXN + 5], b[MAXN + 5];
  17. void init() {
  18. fct[0] = 1; for(int i=1;i<=MAXN;i++) fct[i] = mul(fct[i - 1], i);
  19. ifct[MAXN] = pow_mod(fct[MAXN], MOD - 2);
  20. for(int i=MAXN-1;i>=0;i--) ifct[i] = mul(ifct[i + 1], i + 1);
  21. for(int i=0;i<=MAXN;i++) {
  22. b[i] = (i == 0);
  23. for(int j=0;j<i;j++)
  24. b[i] = sub(b[i], mul(b[j], ifct[i-j+1]));
  25. }
  26. }
  27. int sum(int n, int k) {
  28. int ret = 0; n = add(n, 1);
  29. for(int i=1,pw=n;i<=k+1;i++,pw=mul(pw,n))
  30. ret = add(ret, mul(b[k-i+1], mul(pw, ifct[i])));
  31. if( k == 0 ) ret = sub(ret, 1);
  32. return mul(ret, fct[k]);
  33. }
  34. int a[MAXN + 5];
  35. void solve(int s, int p) {
  36. a[0] = 1;
  37. for(int i=0;i<p;i++) {
  38. int k = sub(s, i);
  39. a[i + 1] = sub(0, a[i]);
  40. for(int j=i;j>=1;j--)
  41. a[j] = sub(mul(k, a[j]), a[j - 1]);
  42. a[0] = mul(k, a[0]);
  43. }
  44. for(int i=0;i<=p;i++)
  45. a[i] = mul(a[i], ifct[p]);
  46. }
  47. int t1[MAXN + 5], t2[MAXN + 5];
  48. void mul(int *A, int *B, int p) {
  49. for(int i=0;i<=p;i++) t1[i] = A[i], t2[i] = B[i], A[i] = 0;
  50. for(int i=0;i<=p;i++)
  51. for(int j=0;j<=i;j++)
  52. A[i] = add(A[i], mul(t1[j], t2[i-j]));
  53. }
  54. int f[MAXN + 5], g[MAXN + 5];
  55. void solve2(int p, ll n, int t) {
  56. for(int i=0;i<=p;i++)
  57. f[i] = 0, g[i] = mul(sum(t, i), ifct[i]);
  58. f[0] = 1;
  59. for(ll i=n;i;i>>=1,mul(g,g,p))
  60. if( i & 1 ) mul(f, g, p);
  61. }
  62. class TrickyInequality{
  63. public:
  64. int countSolutions(ll s, int t, int n, int m) {
  65. int p = m - n, ans = 0;
  66. init(), solve(s % MOD, p), solve2(p, n, t);
  67. for(int i=0;i<=p;i++)
  68. ans = add(ans, mul(a[i], mul(f[i], fct[i])));
  69. return ans;
  70. }
  71. };

@details@

另外,这题好像可以用直接容斥然后构造 k 阶差分公式做到 \(O((n-m)^2)\)(orz 栋爷)。

有空。。。再来填坑?

@topcoder - 2013TCO3A D1L3@ TrickyInequality的更多相关文章

  1. Topcoder SRM570 D1L3 CurvyonRails

    几个样例: 5 5wCCwwwCC....w......www..wReturns: 0 3 3C.w....C.Returns: 1 21 20CC..CCCw.CwC..CC.w.CC.CCCwC ...

  2. @topcoder - SRM766R1 D1L3@ ShortestMissingSubsequences

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个大小为 G 的字符集,并给定一个长度为 N 的字符串 A ...

  3. TopCoder kawigiEdit插件配置

    kawigiEdit插件可以提高 TopCoder编译,提交效率,可以管理保存每次SRM的代码. kawigiEdit下载地址:http://code.google.com/p/kawigiedit/ ...

  4. 记第一次TopCoder, 练习SRM 583 div2 250

    今天第一次做topcoder,没有比赛,所以找的最新一期的SRM练习,做了第一道题. 题目大意是说 给一个数字字符串,任意交换两位,使数字变为最小,不能有前导0. 看到题目以后,先想到的找规律,发现要 ...

  5. TopCoder比赛总结表

    TopCoder                        250                              500                                 ...

  6. Topcoder几例C++字符串应用

    本文写于9月初,是利用Topcoder准备应聘时的机试环节临时补习的C++的一部分内容.签约之后,没有再进行练习,此文暂告一段落. 换句话说,就是本文太监了,一直做草稿看着别扭,删掉又觉得可惜,索性发 ...

  7. TopCoder

    在TopCoder下载好luncher,网址:https://www.topcoder.com/community/competitive%20programming/ 选择launch web ar ...

  8. TopCoder SRM 596 DIV 1 250

    body { font-family: Monospaced; font-size: 12pt } pre { font-family: Monospaced; font-size: 12pt } P ...

  9. 求拓扑排序的数量,例题 topcoder srm 654 div2 500

    周赛时遇到的一道比较有意思的题目: Problem Statement      There are N rooms in Maki's new house. The rooms are number ...

随机推荐

  1. 根据ip查询ip归属地

    http://www.oschina.net/code/snippet_944819_33978 http://www.jb51.net/article/54287.htm public String ...

  2. 基于Netty包中的Recycler实现的对象池技术详解

    一.业务背景 当项目中涉及到频繁的对象的创建和回收的时候,就会出现频繁GC的情况,这时就出现了池化的技术来实现对象的循环使用从而避免对象的频繁回收,Netty包下的Recycler就实现了这一功能.当 ...

  3. ASCII码排序(hdu2000)

    思考:字符串的输入中是不包含空格的,所以可以用scanf_s("%字符类型占位符",&变量名,整型参数)来输入字符串. 因为scanf_s()函数的输入一遇到空格就会停止输 ...

  4. 27-1 分组-having

    group by select * from TblStudent --1.请从学生表中查询出每个班的班级id和班级人数 select tsclassId as 班级id, 班级人数=count(*) ...

  5. 二、Spring装配Bean

    内容 声明bean 构造器注入和Setter方法注入 装配Bean 控制bean的创建和销毁 关键词 装配(wiring) 组件扫描(component scanning) 自动装配(AutoWiri ...

  6. Java IO(四) InputStream 和 OutputStream

    Java IO(四) InputStream 和 OutputStream 一.介绍 InputStream 和 OutputStream 是字节流的超类(父类),都是抽象类,都是通过实例化它们的子类 ...

  7. Rocket - tilelink - mask

    https://mp.weixin.qq.com/s/Gqv09RIgSSg5VKe-wb4aGg   讨论tilelink中使用MaskGen生成mask的用法.   1. tilelink中的ma ...

  8. Rocket - decode - SimplifyDC

    https://mp.weixin.qq.com/s/4uWqBRrMVG6FlnBKmw8U-w   介绍SimplifyDC如何简化解码逻辑.     1. 使用   ​​   简化从mint和m ...

  9. WebServer远程部署

    通过远程部署获取webshell并不属于代码层次的漏洞,而是属于配置性错误漏洞. 1.Tomcat tomcat是一个jsp/Servlet容器 端口号:8080 攻击方法: 默认口令.弱口令,爆破, ...

  10. Java实现 蓝桥杯VIP 算法训练 Hankson的趣味题

    问题描述 Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫Hankson.现 在,刚刚放学回家的Hankson 正在思考一个有趣的问题. 今天在课堂上,老师讲解了如 ...