又是先开T3的做题顺序,搞我心态。以后我必须先看看题了。

整数拆分

定义 \(f_m(n)\) 表示将 \(n\) 表示为若干 \(m\) 的非负整数次幂的和的方案数。例如,当 \(m = 2\) 的时候,\(f_2(4) = 4\),一共有 \(\{1, 1, 1, 1\}, \{1, 1, 2\}, \{2, 2\}, \{4\}\) 这 \(4\) 种方案。

定义 \(g^k_m(n)\) 为 \(k\) 个 \(f_m(n)\) 卷积起来的结果,即:

\[g^k_m(n) = \begin{cases}
f_m(n) & k = 1\\
\sum_{i=0}^n(g_m^{k−1}(i) × f_m(n − i)) & \text{otherwise}
\end{cases}
\]

给定 \(n, m, k\),请求出 \((\sum^n_{i=0} g^k_m(i)) \mod 10^9 + 7\)。

对于所有数据,满足 \(0 ≤ n ≤ 10^{18}, 2 ≤ m ≤ 10^{18}, 1 ≤ k ≤ 20\)。

题解

考场上推生成函数,然而即使推出来了答案的式子我还是不知道怎么做……结果是个DP。

\[f_m=\frac{1}{1-x}\frac{1}{1-x^m}\dots\frac{1}{1-x^{m^{\lfloor\log_mn\rfloor}}}\\
g_m^k=\left(\frac{1}{1-x}\right)^k \left(\frac{1}{1-x^m}\right)^k \dots \left(\frac{1}{1-x^{m^{\lfloor\log_mn\rfloor}}}\right)^k
\]

由于答案是对 \(\sum_{i=0}^ng_m^k(i)\) 求和,所以再乘以一项 \(\frac{1}{1-x}\),那么

\[ans=\left(\frac{1}{1-x}\right)^{k+1} \left(\frac{1}{1-x^m}\right)^k \dots \left(\frac{1}{1-x^{m^{\lfloor\log_mn\rfloor}}}\right)^k [x^n]
\]

然后我就开始想怎么用广义二项式定理推通项公式的事情了。

我想到了对 \(n\) 进行 \(m\) 进制拆分,但是推贡献的时候错了一步。用 \(1\) 去凑 \(2m\) 的方案数并不等于用 \(1\) 去凑 \(m\) 的方案数的平方。

当时我以为有这个关系,然后式子化成了

\[ans_1=\frac{1}{1-ax^m} \left(\frac{1}{1-x^m}\right)^k [x^{m_1}]
\]

然后我就开始仿造斐波那契数列的通项公式的构造过程,列了个方程

\[\frac{t_0}{1-ax^m} + \frac{t_1}{1-x^m} + \frac{t_2x}{1-x^m} + \dots + \frac{1}{t_kx^{k-1}}=
\frac{1}{1-ax^m} \left(\frac{1}{1-x^m}\right)^k
\]

然后我发现它挺好解的,于是写了个高斯消元。最终发现推错的那一步时心态爆炸。

Subtask2

\(n\leq 1000\)

\[f(n)=\begin{cases}
f(n-1) & n\mod m\neq 0\\
f(n-1)+f(n/m) & n\mod m=0
\end{cases}
\]

这个继整数拆分以后的DP方程也很妙啊。

Subtask4

\(k=1\)

可以用的数字一共有 \(1,m,m^2,m^3\dots\) 共 \(\lfloor\log_mn\rfloor\) 个。

令 \(f[i][j]\) 表示用了前 \(i\) 个数字,当前和为 \(j\) 的方案数。

令 \(j=k* m^(i-1)+r,r< m^(i-1)\)

注意到后面的都是前面的倍数,所以无论后面的数字如何选择,都不可能改变 \(r\) 的值,因此可能被用到的 \(j\) 的 一定是 \(k* m^(i-1)+n\mod m^(i-1)\)。

令 \(h[i][j]\) 表示用了前 \(i\) 个数字,当前数字和为 \(j* m^(i-1)+n\mod m^(i-1)\) 的方案。

这样 \(j\) 这一维还是太大。

通过观察和归纳证明,可以得到,对于确定的 \(i\),\(h[i][j]\) 是一个关于 \(j\) 的 \(i\) 次多项式。

于是我们可以只保留前 \(i+1\) 项 DP 值,转移使用插值。

\[h[i][j]=f[i][j\cdot a_i+n\mod a_i]\\
=\sum_{k=0}^jf[i-1][k\cdot a_i+n\mod a_i]\\
=\sum_{k=0}^jf[i-1][k\frac{a_i}{a_{i-1}}a_{i-1}+\left\lfloor\frac{n \mod a_i}{a_{i-1}}\right\rfloor\cdot a_{i-1}+(n\mod a_i)\mod a_{i-1}]\\
=\sum_{k=0}^jh[i-1][k\frac{a_i}{a_{i-1}}+\left\lfloor\frac{n \mod a_i}{a_{i-1}}\right\rfloor]
\]

一共 \(O(\log n)\) 个因数,每次需要做一次插值,\(O(\log n)\) 次求值,复杂度 \(O(\log^3 n)\)。

  1. CO int N=2000+10;
  2. int fac[N],ifac[N];
  3. struct polynomial{
  4. int n,y[N];
  5. int coef[N],pre[N],suf[N];
  6. void init(){
  7. for(int i=1;i<=n;++i){
  8. int sum=mul(ifac[i-1],mul(ifac[n-i],y[i]));
  9. coef[i]=(n-i)&1?mod-sum:sum;
  10. }
  11. }
  12. int calc(int x){
  13. if(x<=n-1) return y[x+1];
  14. pre[0]=1;
  15. for(int i=1;i<=n;++i) pre[i]=mul(pre[i-1],add(x,mod-(i-1)));
  16. suf[n+1]=1;
  17. for(int i=n;i>=1;--i) suf[i]=mul(suf[i+1],add(x,mod-(i-1)));
  18. int ans=0;
  19. for(int i=1;i<=n;++i) ans=add(ans,mul(coef[i],mul(pre[i-1],suf[i+1])));
  20. return ans;
  21. }
  22. }h[N];
  23. LL pw[N];int lg;
  24. LL a[N];int cnt;
  25. int main(){
  26. freopen("split.in","r",stdin),freopen("split.out","w",stdout);
  27. LL n=read<LL>(),m=read<LL>();
  28. int K=read<int>();
  29. lg=0,pw[0]=1;
  30. for(;pw[lg]<=n/m;++lg) pw[lg+1]=pw[lg]*m;
  31. cnt=0,a[0]=1;
  32. for(int i=0;i<=lg;++i)
  33. for(int j=1;j<=K;++j) a[++cnt]=pw[i];
  34. fac[0]=1;
  35. for(int i=1;i<=cnt;++i) fac[i]=mul(fac[i-1],i);
  36. ifac[cnt]=fpow(fac[cnt],mod-2);
  37. for(int i=cnt-1;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
  38. h[0].n=1,h[0].y[1]=1;
  39. h[0].init();
  40. for(int i=1;i<=cnt;++i){
  41. h[i].n=i+1;
  42. LL r=n%a[i]/a[i-1];
  43. for(int j=0;j<=i;++j){
  44. h[i].y[j+1]=h[i-1].calc((a[i]/a[i-1]*j+r)%mod);
  45. h[i].y[j+1]=add(h[i].y[j],h[i].y[j+1]);
  46. }
  47. h[i].init();
  48. }
  49. printf("%d\n",h[cnt].calc((n/a[cnt])%mod));
  50. return 0;
  51. }

我觉得如果我能猜到那个生成函数的系数是多项式的话,我还是做得出来的。但毕竟见识太少,我只会中规中矩的方法,不会直接想到拉格朗日插值和BM算法。

多项式证明

首先 \(\frac{1}{1-x}\) 的系数是多项式。

通过打表找规律,两个系数是多项式的生成函数卷积后的生成函数的系数也是多项式。\(n\) 次的多项式乘以 \(m\) 次的多项式得到的是 \(n+m+1\) 次的多项式。

那么 \((\frac{1}{1-x})^{k+1}\) 就是一个 \(k\) 次多项式。往 \(\frac{1}{1-x^m}\) 合并的时候,我们只会用 \(x\) 的次数是 \(m\) 的自然数倍的项,分离常数后它还是一个 \(k\) 次多项式;但是 \(\frac{1}{1-x^m}\) 分离常数后变成了 \(0\) 次多项式,所以 \((\frac{1}{1-x})^{k+1} (\frac{1}{1-x^m})^k\) 就是一个 \(2k\) 次多项式。

如此归纳下去,就可证明那个 DP 状态一直是多项式了。

简单计数

给定一个长度为 \(n\) 的序列 \(s\)。共询问 \(m\) 次,每次询问给定一个数字 \(k\) 和一个固定长度 \(l\),以及 \(k\) 个 整数 \(x_1, x_2, \dots, x_k\)。请求出,如果将区间 \([x_1, x_1 + l − 1],[x_2, x_2 + l − 1],\dots,[x_k, x_k + l − 1]\) 按照顺序前后 拼接在一起得到的序列中,有多少回文子串,序列从 \(1\) 开始编号。回文子串的定义是,这个序列从前往 后和从后往前是一样的。

对于所有数据,满足 \(n ≤ 10^5 , m ≤ 10^5 , ∑k ≤ 10^5 , ∑k × l ≤ 10^9 , x_i + l − 1 ≤ n, 1 ≤ s_i ≤ n\)。

题解

咕咕咕。

排序

给出一个长度为 \(n\) 的整数序列,你能够使用的操作只有 \(\text{rev}(l, r)\),表示将闭区间 \([l, r]\) 内的数字翻转,需要的代价是 \(r − l + 1\), 你需要在 \(4 × 10^6\) 的代价内最大化最终序列的 LIS 长度,LIS 表示最长上升子序列。

只有你使用的操作的代价不超过限制,并且最终得到的序列的 LIS 和理论上能够得到的最大值一样 的时候,才可以得分。

对于所有数据,满足 \(n ≤ 32000, 0 ≤ 序列中的数字 ≤ 32000\)。

题解

题目让你最大化LIS,然而其实完全可以排好序……所以说我们要有大胆猜结论的能力。并且这道题是考场上AC人数最多的。

Subtask3

考虑 01 序列如何排序。其实归并排序就可以,每次我们把左区间所有的 1 和右区间所有的 0 ,交换一下。

  1. 0101
  2. 0011

值域 \([0,5]\) 同理,我们可以每次把一种数字分出来。

  1. 012345012345
  2. 012344321055
  3. 001234432155
  4. 001123443255
  5. 001122344355
  6. 001122334455

复杂度 \(O(6n\log n)\)。

Subtask4

值域较大,对所有数字再进行一次分治即可。

具体而言,就是按位从高到低做。有点像倒着的基数排序。

  1. CO int N=32000+10;
  2. int a[N];
  3. vector<pair<int,int> > sol;
  4. void reverse(int l,int r){
  5. reverse(a+l,a+r+1);
  6. sol.push_back(make_pair(l,r));
  7. }
  8. void sol01(int l,int r,int w){
  9. if(l==r) return;
  10. int mid=(l+r)>>1;
  11. sol01(l,mid,w),sol01(mid+1,r,w);
  12. int ql=0;
  13. for(int i=mid;i>=l;--i)
  14. if(a[i]>>w&1) ql=i;
  15. int qr=0;
  16. for(int i=mid+1;i<=r;++i)
  17. if(~a[i]>>w&1) qr=i;
  18. if(ql and qr) reverse(ql,qr);
  19. }
  20. void solve(int l,int r,int w){
  21. if(l>r or w==-1) return;
  22. sol01(l,r,w);
  23. int mid=0;
  24. for(int i=l;i<=r;++i)
  25. if(~a[i]>>w&1) mid=i;
  26. if(!mid) solve(l,r,w-1);
  27. else solve(l,mid,w-1),solve(mid+1,r,w-1);
  28. }
  29. int main(){
  30. freopen("rev.in","r",stdin),freopen("rev.out","w",stdout);
  31. int n=read<int>();
  32. for(int i=1;i<=n;++i) read(a[i]);
  33. solve(1,n,14);
  34. printf("%zd\n",sol.size());
  35. for(int i=0;i<(int)sol.size();++i)
  36. printf("%d %d\n",sol[i].first,sol[i].second);
  37. return 0;
  38. }

test20191205 WC模拟赛的更多相关文章

  1. NOI.AC WC模拟赛

    4C(容斥) http://noi.ac/contest/56/problem/25 同时交换一行或一列对答案显然没有影响,于是将行列均从大到小排序,每次处理限制相同的一段行列(呈一个L形). 问题变 ...

  2. NOIp2018模拟赛四十二

    今天看标题终于回到了“NOIP模拟赛”,十分高兴啊! 然后一打开题目: ********** 所以今天又是一场NOIPlus模拟赛(微笑) 成绩:0+70+0=70 A题想了个贪心被myh两分钟cha ...

  3. 冲刺$\mathfrak{CSP-S}$集训模拟赛总结

    开坑.手懒并不想继续一场考试一篇文. 既没必要也没时间侧边栏的最新随笔题解反思相间也丑 而且最近越来越懒了竟然都不写题解了……开坑也是为了督促自己写题解. 并不想长篇大论.简要题解也得写啊QAQ. 目 ...

  4. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  5. NOI模拟赛 Day1

    [考完试不想说话系列] 他们都会做呢QAQ 我毛线也不会呢QAQ 悲伤ING 考试问题: 1.感觉不是很清醒,有点困╯﹏╰ 2.为啥总不按照计划来!!! 3.脑洞在哪里 4.把模拟赛当作真正的比赛,紧 ...

  6. NOIP第7场模拟赛题解

    NOIP模拟赛第7场题解: 题解见:http://www.cqoi.net:2012/JudgeOnline/problemset.php?page=13 题号为2221-2224. 1.car 边界 ...

  7. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  8. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  9. 小奇模拟赛9.13 by hzwer

    2015年9月13日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿(explo) [题目背景] 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞 ...

随机推荐

  1. 浅析PHP框架Laravel最新SQL注入漏洞

    PHP知名开发框架Laravel,之前在官方博客通报了一个高危SQL注入漏洞,这里简单分析下. 首先,这个漏洞属于网站coding写法不规范,官方给了提示: 但官方还是做了修补,升级最新版本V5.8. ...

  2. ES6高级技巧(二)

    Array.from const cities = [ { name: 'Milan', visited: 'no' }, { name: 'Palermo', visited: 'yes' }, { ...

  3. Lua table concat

    [1]table concat 简介 使用方式: table.concat(table, sep, start, end) 作用简介: concat是concatenate(连锁.连接)的缩写. ta ...

  4. TP5接口开发之异常处理接管

    前几天在开发的时候用到了第三方的扩展包,使用过程中第三方扩展包抛出了异常 因为这边是接口开发,需要返回错误代码以及提示信息等,所以就需要接管异常处理. 此文章只做笔记,有不对或不详细的地方欢迎大家留言 ...

  5. golang ----并发 && 并行

    Go 语言的线程是并发机制,不是并行机制. 那么,什么是并发,什么是并行? 并发是不同的代码块交替执行,也就是交替可以做不同的事情. 并行是不同的代码块同时执行,也就是同时可以做不同的事情. 举个生活 ...

  6. - XML 解析 总结 DOM SAX PULL MD

    目录 目录 XML 解析 总结 DOM SAX PULL MD 几种解析方式简介 要解析的内容 DOM 解析 代码 输出 SAX 解析 代码 输出 JDOM 解析 代码 输出 DOM4J 解析 代码 ...

  7. 【JVM学习笔记二】垃圾收集器与内存分配策略

    1. 概述 1) GC的历史比Java久远 2) GC需要完成的三件事: | 哪些内存需要回收 | 什么时候回收 | 如何回收 3) Java内存运行时区域各个部分: | Java虚拟机栈.计数器.本 ...

  8. tomcat添加https服务

    系统环境: centos6.7 jdk-7u79-linux-x64 apache-tomcat-7.0.57 apr-1.5.2 apr-util-1.5.4 一.tomcat安装 自己准备tomc ...

  9. JavaScript 之 节点操作

    一.文档树结构 DOM 可以将任何 HTML 或 XML 描绘成一个由多层节点构成的结构. 节点分为不同的类型,每种类型分别表示文档中不同的信息.每个节点都拥有各自的特点.数据和方法,另外也与其他节点 ...

  10. Springboot jpa多数据源

    1.SpringBootApplication package com.xx.xxx; import org.springframework.beans.factory.annotation.Auto ...