没考虑重复lcm处理被卡TLE没A真是可惜

题目大意

$n$为$k-可表达的$当且仅当数$n$能被表示成$n$的$k$个因子之和,其中$k$个因子允许相等。

求$[A,B]$之间$k-可表达$的数的个数

$T \le 5*10^4,2 \le K \le 7,1 \le A \le B \le 10^{18}$


题目分析

每一种拆分可以视作$1=\frac{1}{a}+\frac{1}{b}+...$的形式。因为K相当小,可以先搜出每个$K$下的拆分情况,问题就转化成了求$[l,r]$之间有多少数至少是其中一个的倍数——这是一个相当经典的问题。

但是这题的数据范围要求进一步细节优化。

注意到在极限数据$K=7,T=5*10^4$下,纯粹地$2^{因数}$枚举每一种情况lcm的做法相当低效。通过观察/经验会发现,这$2^{因数}$个lcm有大量是重复的。那么我们就转而保存每个lcm的系数而非把lcm全部存下来。

这是一个计算倍数容斥问题时,显著而不甚易想起的优化。

代码很丑。没心情重构。

 #include<bits/stdc++.h>
const int ass5[] = {, , , , , , };
const int ass6[] = {, , , , , , };
const int ass7[] = {, , , , , , , , , , , , , , , };
typedef long long ll; int T;
ll l,r,k,gmpAss5[],gmpAss6[],gmpAss7[]; ll read()
{
char ch = getchar();
ll num = , fl = ;
for (; !isdigit(ch); ch = getchar())
if (ch=='-') fl = -;
for (; isdigit(ch); ch = getchar())
num = (num<<)+(num<<)+ch-;
return num*fl;
}
int gcd(int a, int b){return !b?a:gcd(b, a%b);}
ll assp5(ll x)
{
ll ret = ;
for (int i=; i<; i++)
ret += x/gmpAss5[i];
return ret;
}
ll assp6(ll x)
{
ll ret = ;
for (int i=; i<; i++)
ret += x/gmpAss6[i];
return ret;
}
ll assp7(ll x)
{
ll ret = ;
for (int i=; i<=gmpAss7[]; i++)
if (gmpAss7[i]) ret += x/gmpAss7[i];
return ret;
}
void makeAss5()
{
for (int i=, ass=; i<(<<(ass)); i++)
{
ll dt = , lst = , del;
for (int j=, t=i; j<=ass; j++, t>>=)
if (t&){
++dt, del = gcd(lst, ass5[j]);
lst *= ass5[j]/del;
}
gmpAss5[i] = (dt&)?lst:-lst;
}
}
void makeAss6()
{
for (int i=, ass=; i<(<<(ass)); i++)
{
ll dt = , lst = , del;
for (int j=, t=i; j<=ass; j++, t>>=)
if (t&){
++dt, del = gcd(lst, ass6[j]);
lst *= ass6[j]/del;
}
gmpAss6[i] = (dt&)?lst:-lst;
}
}
void makeAss7()
{
ll &tot = gmpAss7[];
for (int i=, ass=; i<(<<(ass)); i++)
{
ll dt = , lst = , del;
for (int j=, t=i; j<=ass; j++, t>>=)
if (t&){
++dt, del = gcd(lst, ass7[j]);
lst *= ass7[j]/del;
}
lst = (dt&)?lst:-lst;
bool chk = ;
for (int i=; i<=tot&&chk; i++)
if (gmpAss7[i]==-lst) gmpAss7[i] = , chk = ;
if (chk) gmpAss7[++tot] = lst;
}
}
ll calc(ll x, ll k)
{
ll ret = ;
if (k==) return x;
if (k==) return x>>;
if (k==) return (x/+x/-x/);
if (k==) return (x/+x/+x/-x/-x/-x/+x/);
if (k==) return assp5(x);
if (k==) return assp6(x);
if (k==) return assp7(x);
return ret;
}
void write(ll x){if (x/) write(x/);putchar(x%+'');}
int main()
{
makeAss5(), makeAss6(), makeAss7();
for (scanf("%d",&T); T; --T)
{
l = read(), r = read(), k = read();
write(calc(r, k)-calc(l-, k)), putchar('\n');
}
return ;
}

END

最新文章

  1. RHEL6.4 + Oracle 11g DG测试环境快速搭建参考
  2. iOS 属性修饰符记录 --不定时更新
  3. BLE 蓝牙协议栈开发
  4. showModalDialog打开页面有缓存,不走action
  5. ZeroMQ接口函数之 :zmq_msg_data - 返回消息内容的指针
  6. C#通过SSH连接MySql
  7. linux shell 脚本攻略学习19--sed命令详解
  8. [Android] Android Sutdio on Surface Pro 3
  9. FZU 2214 Knapsack problem(背包问题)
  10. 帕金森定律(Parkinson&#39;s Law)
  11. java高级工程师必备知识
  12. 我与Bootstrap
  13. vi常用命令与设置(不断修改中)
  14. IronPython 源码剖析系列(2):IronPython 引擎的运作流程
  15. Acquire and Release Semantics
  16. 一个好的函数(gcd)求最小公约数
  17. mongoDB数据库的简单使用
  18. 移动端tab滑动和上下拉刷新加载
  19. 11个不常被提及的JavaScript小技巧
  20. IDEA查看类继承关系及生成类关系图

热门文章

  1. Mac下通过homebrew安装maven
  2. Ubuntu 最新设置阿里云更新源
  3. CF438D The Child and Sequence 线段树
  4. H.天神的密码
  5. hdu6070Dirt Ratio 多校题 套路二分
  6. PHPstudy安装redis扩展
  7. Java通过图片url地址获取图片base64位字符串的两种方式
  8. 初学Vue.js(2.x版本)
  9. &lt;Android HAL 之路&gt; HAL 简介
  10. pycharm使用秘籍 和 pip命令