[计蒜之道 复赛2017] 题解 (只有 A,E 两题)
2017-06-12 21:57
330 查看
前言:菜鸡博主打了一波计蒜之道,A了B,D,F3个水题后并不能取得什么进展(沉迷A题卡常无法自拔)
因为罚时爆炸,rk200+滚粗,%%%rk34的红太阳ZZT(听说ZZT如果不是漏掉了E的特判,就切5题rk20-了),
听说C题是毛爷爷FFT,一脸懵逼.JPG,于是决定把A和E给补了。
A题:考虑进行数位dp,求L-R满足条件的数字个数,就是等价于求F(R)-F(L-1).
F(x)的求法:
这个做法还是很符合一般数位dp的套路的,
将x表示为p进制后,从高位向低位考虑,
当处理到第i位时,统计第i位之前所有位(就是更高位)都与x相同,
而第i位取值小于x在第i位的取值 并符合题意的数字的个数,
写成式子即为:F(x)+=dp[j][i-1],其中,j是满足与(i-1)位的数字互质并小于x在第i位取值的数,
这样,dp数组预处理一下,最后再判断一下x本身是否符合题意就可以求出F(x)的值了。
dp[i][j]表示后面还有i位没有填,最高位的数字是j的方案数,
dp转移方程是:dp[i][j]=sigma(dp[i-1][k]),其中k是与j互质并且小于p的所有数字,边界情况是dp[0][j]=1.
但是,如果直接进行转移,dp的预处理是O(p^2logpR)的,因为有50组数据都有10^3<p<=10^5,暴力求dp显然会TLE.
考虑dp求解的优化,在求第i维dp数组的值的时候,这p个值都是只与第(i-1)维的值有关的,
于是考虑通过莫比乌斯反演优化这样有关互质的dp过程,
dp[i][j]=sigma((gcd(j,k)==1),dp[i-1][k]),
则有dp[i][j]=sigma(d|j,miu[d]*sigma(d|k,dp[i-1][k])),
通过预处理出前缀和,可以在O(nlog2plogpR)=O(nlog2R)时间内求出最终的答案,从而可以通过此题。
正确性:如果k对j没有产生贡献,则显然j,k的最大公约数能写成几个质数之积,
4000
利用容斥原理不难发现,假设j,k的最大公约数由r种质数组成,
则其对答案最终的贡献就是1-C(r,1)+C(r,2)-C(r,3)+....C(r,r).
可以发现这个数字最终等于0,
而k对j有贡献时,只有在d=1时计算了一次,贡献为1,也是正确的,
由此可以优化这样的dp求解过程。
Code:
E.先通过组合数的方法,得到本题的公式:
令n=(x+y)/2,
则ans=sigma(i=0...n,C(x-i,i)*C(x-2*i,n-i)).
但是这样爆算的话,时间复杂度会爆炸,
所以考虑利用模数很小(p=100003)的性质去解决,
Lucas定理带入后,上面和式的每一项可以写成C((x-i)%p,i%p)*C((x-2*i)%p,(n-i)%p)*C((x-i)/p,i/p)*C((x-2*i)/p,(n-i)/p).
将上面4个式子分别标号为A(i),B(i),C(i),D(i).
A(i+p)=C((x-i-p)%p,(i+p)%p)=C((x-i)%p,i%p)=A(i)
B(i+p)=C((x-2*i-2*p)%p,(n-i-p)%p)=C((x-2*i)%p,(n-i)%p)=B(i)
这样第i,i+p,i+2p....项就可以进行合并了,而C(i)*D(i)的部分可以这样迭代下去继续算,
预处理一下阶乘和阶乘的逆元就可以O(plogpX)解决此题。
Code:
因为罚时爆炸,rk200+滚粗,%%%rk34的红太阳ZZT(听说ZZT如果不是漏掉了E的特判,就切5题rk20-了),
听说C题是毛爷爷FFT,一脸懵逼.JPG,于是决定把A和E给补了。
A题:考虑进行数位dp,求L-R满足条件的数字个数,就是等价于求F(R)-F(L-1).
F(x)的求法:
这个做法还是很符合一般数位dp的套路的,
将x表示为p进制后,从高位向低位考虑,
当处理到第i位时,统计第i位之前所有位(就是更高位)都与x相同,
而第i位取值小于x在第i位的取值 并符合题意的数字的个数,
写成式子即为:F(x)+=dp[j][i-1],其中,j是满足与(i-1)位的数字互质并小于x在第i位取值的数,
这样,dp数组预处理一下,最后再判断一下x本身是否符合题意就可以求出F(x)的值了。
dp[i][j]表示后面还有i位没有填,最高位的数字是j的方案数,
dp转移方程是:dp[i][j]=sigma(dp[i-1][k]),其中k是与j互质并且小于p的所有数字,边界情况是dp[0][j]=1.
但是,如果直接进行转移,dp的预处理是O(p^2logpR)的,因为有50组数据都有10^3<p<=10^5,暴力求dp显然会TLE.
考虑dp求解的优化,在求第i维dp数组的值的时候,这p个值都是只与第(i-1)维的值有关的,
于是考虑通过莫比乌斯反演优化这样有关互质的dp过程,
dp[i][j]=sigma((gcd(j,k)==1),dp[i-1][k]),
则有dp[i][j]=sigma(d|j,miu[d]*sigma(d|k,dp[i-1][k])),
通过预处理出前缀和,可以在O(nlog2plogpR)=O(nlog2R)时间内求出最终的答案,从而可以通过此题。
正确性:如果k对j没有产生贡献,则显然j,k的最大公约数能写成几个质数之积,
4000
利用容斥原理不难发现,假设j,k的最大公约数由r种质数组成,
则其对答案最终的贡献就是1-C(r,1)+C(r,2)-C(r,3)+....C(r,r).
可以发现这个数字最终等于0,
而k对j有贡献时,只有在d=1时计算了一次,贡献为1,也是正确的,
由此可以优化这样的dp求解过程。
Code:
#include <bits/stdc++.h> #define ll long long using namespace std; ll dp[65][100005]; ll s[100005]; ll p; int prime[100001],cnt=0,miu[100001]; bool taig[100001]; void getmiu() {int i,j; miu[1]=1; for (i=2;i<=100000;i++) {if (taig[i]==0) {cnt++;prime[cnt]=i;miu[i]=-1;} for (j=1;j<=cnt&&i*prime[j]<=100000;j++) {taig[i*prime[j]]=1; if (i%prime[j]!=0) {miu[i*prime[j]]=miu[i]*(-1);} else {miu[i*prime[j]]=0;break;} } } return; } ll gcd(ll a,ll b) {if (a==0||b==0) {return 0;} if (a%b==0) return b; return gcd(b,a%b); } inline void cal(int w) {int i,j,k; for (i=1;i<p;i++) {dp[0][i]=1;} for (k=1;k<=w;k++) {for (i=1;i<p;i++) {s[i]=0;dp[k][i]=0; {for (j=i;j<p;j+=i) {s[i]+=dp[k-1][j];} } } for (i=1;i<p;i++) {if (miu[i]!=0) {s[i]*=miu[i]; for (j=i;j<p;j+=i) {dp[k][j]+=s[i];} } } } return; } ll ans=0; int tag=1; int getans(ll num,int w) {int i,j; if (num<p) {cal(w); for (i=1;i<num;i++) {ans+=dp[w][i];} for (i=1;i<p;i++) {for (j=0;j<w;j++) {ans+=dp[j][i];} } return num; } int lar=getans(num/p,w+1); int m=num%p; if (tag) {for (i=1;i<m;i++) {if (gcd(i,lar)==1) {ans+=dp[w][i];} } } if (gcd(m,lar)!=1) {tag=0;} return m; } int getans2(ll num,int w) {int i,j; if (num<p) {for (i=1;i<num;i++) {ans+=dp[w][i];} for (i=1;i<p;i++) {for (j=0;j<w;j++) {ans+=dp[j][i];} } return num; } int lar=getans2(num/p,w+1); int m=num%p; if (tag) {for (i=1;i<m;i++) {if (gcd(i,lar)==1) {ans+=dp[w][i];} } } if (gcd(m,lar)!=1) {tag=0;} return m; } int main (){ getmiu(); int test; ll l,r; int i; scanf ("%d",&test); while (test--) {scanf ("%lld%lld%lld",&l,&r,&p); ans=0;tag=1;getans(r,0); if (tag) {ans++;} ll tp=ans; if (l>1) {ans=0;tag=1;getans2(l-1,0); if (tag) {ans++;} } else {ans=0;} printf ("%lld\n",tp-ans); } return 0; }
E.先通过组合数的方法,得到本题的公式:
令n=(x+y)/2,
则ans=sigma(i=0...n,C(x-i,i)*C(x-2*i,n-i)).
但是这样爆算的话,时间复杂度会爆炸,
所以考虑利用模数很小(p=100003)的性质去解决,
Lucas定理带入后,上面和式的每一项可以写成C((x-i)%p,i%p)*C((x-2*i)%p,(n-i)%p)*C((x-i)/p,i/p)*C((x-2*i)/p,(n-i)/p).
将上面4个式子分别标号为A(i),B(i),C(i),D(i).
A(i+p)=C((x-i-p)%p,(i+p)%p)=C((x-i)%p,i%p)=A(i)
B(i+p)=C((x-2*i-2*p)%p,(n-i-p)%p)=C((x-2*i)%p,(n-i)%p)=B(i)
这样第i,i+p,i+2p....项就可以进行合并了,而C(i)*D(i)的部分可以这样迭代下去继续算,
预处理一下阶乘和阶乘的逆元就可以O(plogpX)解决此题。
Code:
相关文章推荐
- NOIP2017普及组复赛题解
- 2017 百度之星复赛题解 01、03、05
- 2017百度之星程序设计大赛 - 复赛 题解(1,3)
- 2017计蒜之道程序设计大赛复赛题解
- Noip2017复赛游记(爆炸记)
- 【提高组NOIP2017】时间复杂度 题解 分治系统处理
- 2016"百度之星" - 复赛(Astar Round3) 题解 (待续)
- Hdu6146 Pokémon GO(2017百度之星程序设计大赛 - 复赛)
- HDU6147 Pokémon GO II (2017百度之星程序设计大赛 - 复赛)
- (状压dp)2017 计蒜之道 复赛 F. 腾讯消消乐
- 2017 计蒜之道 复赛 题解
- 2017 计蒜之道 复赛 百度地图导航 (拆点+最短路)
- 2017第八届蓝桥杯 C/C++C组真题及题解
- ZOJ 1298题解,想到算法就不难了,要求多米诺骨牌最后落下的位置。这是Dijkstra算法的简单应用。设立的几个关键点,都是从1开始倒比如只有两个点1 2,最后牌倒得位置是2
- 【拓展Euclid】(2017)第八届蓝桥杯省赛) C/C++ A组 题解(第八题)
- NOIP2017提高组初赛题解
- 数人云|PaaS Innovation 2017 云计算大会那么多,关心PaaS只有它
- 2017百度之星复赛:1006. Valley Numer(数位DP)
- 2017 计蒜之道 复赛 腾讯消消乐【状压dp】
- 2017广东工业大学程序设计竞赛决赛 题解&源码(A,数学解方程,B,贪心博弈,C,递归,D,水,E,贪心,面试题,F,贪心,枚举,LCA,G,dp,记忆化搜索,H,思维题)