热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HDU6102(树状数组+容斥+离线处理)

GCDispowerTimeLimit:100005000MS(JavaOthers)MemoryLimit:6553665536K(JavaOthers)T

GCDispower Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 141    Accepted Submission(s): 70


Problem Description
There is a mysterious organization called GCD. They get a permutation P, permutation is a sequence of length N, only consists of number 1 to N and each number appears only once.
They want to gain magic power from this permutation. For the interval [L, R] they can get power:
i=LRj=i+1Rk=j+1R(gcd(P[i],P[j])==P[k])P[k]
Now they have M queries, for each query can you help them calculate how many power they can get?
 

Input
The first line is an integer T which indicates the case number.
And as for each case, first line is two integer N and M which indicates the length of permutation and number of query.
Next line is N integer which indicate the permutation P
Next M line, for each line is two integer L and R which indicate each query.

Limit
1T100
1N,M100000
1PiN, for any pair  (i,j) PiPj
1LiRiN

About 95% test case:  1N1000
Other test case:  1N100000
 

Output
As for each case, you need to output M integer which indicate the answer of each query.
 

Sample Input
 
  
23 13 2 11 36 36 5 4 3 2 11 62 63 5
 

Sample Output
 
  
1850
 

Source
2017 Multi-University Training Contest - Team 6
题意:给你一个序列,然后给你若干个询问,每个询问一个区间[l,r],问你这个区间的价值是多少,一个区间的价值我们定义为,若这个区间存在一个三元组i, j, k,使得gc(a[i], a[[j]) == a[k],则这个区间的价值加上a[k],(刚开始为0)。

解题思路:我们肯定是要把这些询问离线处理,然后一个最重要的一点是要枚举a[k],从左到右,我们可以知道如果gcd(a[i], a[j])  == a[k],则a[i] / a[k], 与a[j] / a[k] ,一定互质,所以我们肯定要枚举a[k]的倍数,并且位置在k的前面,处理出所有的倍数之后,我们从右往左扫,假如我们每次知道当前有多少对互质的数假设为x,我们就知道对区间左端点的贡献为x * a[k],我们可以用一个树状数组,或者线段树来维护一下就行, 关键是怎样知道当前有多少对互质的数,我们可以用容斥求出,我们可以每次记录一个数进行素数分解之后的所有可能的质因子乘积,然后后面的数通过容斥原理,先进行素数分解,然后枚举gcd为他的每一个质因子的倍数,这些数一定与当前数不互质,用总的数的个数减去这些数就行,我们可以用容斥求这些集合的并。

#include 
using namespace std;
typedef long long ll;
const int maxn = 100000 + 10;
int N, M;
vector prime[maxn];//素数分解,之后的质因子
bool valid[maxn];//素数筛选
int a[maxn];//原数组
int Hash[maxn];//元素i在原数组的位置
vector> query[maxn];//query[i]表示以i为右端点的区间,query[i][j].first表示询问id,query[i][j].second表示询问区间的左端点
ll ans[maxn];//用于容斥的数组,ans[i]表示i在之前出现过的次数
vector> status[maxn];//stastus[i][j].first表示状态的大小,second表示容斥的符号
ll Tree[maxn];//树状数组
ll result[maxn];//保存结果
int temp[maxn];//辅助数组
int lowbit(int x)
{
return x&(-x);
}
void add(int loc, ll value)
{
for(int i = loc; i <= N; i += lowbit(i))
{
Tree[i] += value;
}
}
void update(int l, int r, ll value)
{
add(l, value);
add(r + 1, -value);
}
ll get(int loc)
{
ll res = 0;
for(int i = loc; i >= 1; i -= lowbit(i))
{
res += Tree[i];
}
return res;
}
void updateAns(int x, ll value)
{
for(int i = 0; i {
ans[status[x][i].first] += value;
}
}
ll getAns(int x)
{
ll res = 0;
for(int i = 0; i {
res += ans[status[x][i].first] * status[x][i].second;
}
return res;
}
void initPrime()
{
memset(valid, true, sizeof(valid));
for(int i = 0; i {
prime[i].clear();
status[i].clear();
}
for(int i = 2; i {
if(valid[i])
{
for(int j = i; j {
valid[j] = false;
prime[j].push_back(i);
}
}
}
for(int i = 1; i {
for(int j = 0; j <(1<<(prime[i].size())); j++)
{
status[i].push_back(make_pair(1, 1));
for(int k = 0; k {
int num = (j>>k)&1;
if(num)
{
status[i][j].first *= prime[i][k];
status[i][j].second *= -1;
}
}
}
}
}
void init()
{
memset(Tree, 0, sizeof(Tree));
memset(ans, 0, sizeof(ans));
for(int i = 1; i <= N; i++)
{
query[i].clear();
}
}
int main()
{
initPrime();
//cout<<"initPrime sucess"< int T;
scanf("%d", &T);
while(T--)
{
scanf("%d%d", &N, &M);
init();
for(int i = 1; i <= N; i++)
{
scanf("%d", &a[i]);
Hash[a[i]] = i;
}
int l, r;
for(int i = 1; i <= M; i++)
{
scanf("%d%d", &l, &r);
query[r].push_back(make_pair(i, l));
}
for(int i = 1; i <= N; i++)//枚举左端点,计算对右端点的贡献
{
int cnt = 0;
for(int j = 2 * a[i]; j <= N; j += a[i])//枚举a[i]的倍数
{
if(Hash[j] }
sort(temp + 1, temp + cnt + 1);//对位置进行排序,便于从右往左扫
ll sum = 0;
temp[0] = 0;
for(int j = cnt; j >= 1; j--)
{
sum += getAns(a[temp[j]] / a[i]) * a[i];
updateAns(a[temp[j]] / a[i], 1);//更新容斥
if(j != 1)
update(temp[j - 1] + 1, temp[j], sum);//更新对左区间的贡献
else if(temp[1] == 1) update(1, 1, sum);
else update(1, temp[1], sum);
}
for(int j = cnt; j >= 1; j--)
{
updateAns(a[temp[j]] / a[i], -1);//还原容斥
}
for(int j = 0; j {
result[query[i][j].first] = get(query[i][j].second);
}
}
for(int i = 1; i <= M; i++)
{
printf("%lld\n", result[i]);
}
}
return 0;
}





推荐阅读
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 猜字母游戏
    猜字母游戏猜字母游戏——设计数据结构猜字母游戏——设计程序结构猜字母游戏——实现字母生成方法猜字母游戏——实现字母检测方法猜字母游戏——实现主方法1猜字母游戏——设计数据结构1.1 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了Swing组件的用法,重点讲解了图标接口的定义和创建方法。图标接口用来将图标与各种组件相关联,可以是简单的绘画或使用磁盘上的GIF格式图像。文章详细介绍了图标接口的属性和绘制方法,并给出了一个菱形图标的实现示例。该示例可以配置图标的尺寸、颜色和填充状态。 ... [详细]
  • 本文详细解析了JavaScript中相称性推断的知识点,包括严厉相称和宽松相称的区别,以及范例转换的规则。针对不同类型的范例值,如差别范例值、统一类的原始范例值和统一类的复合范例值,都给出了具体的比较方法。对于宽松相称的情况,也解释了原始范例值和对象之间的比较规则。通过本文的学习,读者可以更好地理解JavaScript中相称性推断的概念和应用。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • springmvc学习笔记(十):控制器业务方法中通过注解实现封装Javabean接收表单提交的数据
    本文介绍了在springmvc学习笔记系列的第十篇中,控制器的业务方法中如何通过注解实现封装Javabean来接收表单提交的数据。同时还讨论了当有多个注册表单且字段完全相同时,如何将其交给同一个控制器处理。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Ihavethefollowingonhtml我在html上有以下内容<html><head><scriptsrc..3003_Tes ... [详细]
author-avatar
手机用户2502893987
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有