Gcd & Lcm game

问题描述 :

Tired of playing too much computer games, alpc23 is planning to play a game on numbers. Because plus and subtraction is too easy for this gay, he wants to do some gcd and lcm operations in a number sequence. After playing it a few times, he has found it is also too boring. So he plan to do a more challenge job: he wants to change several numbers in this sequence and also work out the gcd or lcm of all the number in a subsequence of the whole sequence.
  To be a friend of this gay, you have been invented by him to play this interesting game with him. Of course, you need to work out the answers faster than him to get a free lunch, He he…

输入:

There are multiple test cases.
For each test case.The first line is the length of sequence n, and the number of queries q. (1<=n, q<=100000) The second line has n numbers, they are the initial n numbers of the sequence a1,a2, …,an,
From the third line to the q+2 line are the description of the q operations. They are the one of the two forms:
L k1 k2 p; you need to work out the value after mod p of lcm of the subsequence from k1 to k2, inclusive. (1<=k1<=k2<=n)
G k1 k2 p; you need to work out the value after mod p of gcd of the subsequence from k1 to k2, inclusive. (1<=k1<=k2<=n)
C k v; the k-th number of the sequence has been changed to v.
You can assume that all the numbers before and after the replacement are positive and no larger than 100.

输出:

There are multiple test cases.
For each test case.The first line is the length of sequence n, and the number of queries q. (1<=n, q<=100000) The second line has n numbers, they are the initial n numbers of the sequence a1,a2, …,an,
From the third line to the q+2 line are the description of the q operations. They are the one of the two forms:
L k1 k2 p; you need to work out the value after mod p of lcm of the subsequence from k1 to k2, inclusive. (1<=k1<=k2<=n)
G k1 k2 p; you need to work out the value after mod p of gcd of the subsequence from k1 to k2, inclusive. (1<=k1<=k2<=n)
C k v; the k-th number of the sequence has been changed to v.
You can assume that all the numbers before and after the replacement are positive and no larger than 100.

样例输入:

6 4
1 2 4 5 6 3
L 2 5 17
G 4 6 4
C 4 9
G 4 6 4

样例输出:

9
1
3

一道还不错的题目,解法:线段树+位压缩

题意:

给定一个长度为n的序列m次操作,操作的种类一共有三种

  • 查询

    • L :查询一个区间的所有的数的最小公倍数modp
    • G :查询一个区间的所有的数的最大公约数modp
  • 修改 
    • C :将给定位置的值修改成x

分析:

首先我们注意一下数据的范围,保证数据不超过100,那么很明显素因子特别少一共只有25个,我们可以用线段树维护一下对应素因子的最大值与最小值。更新的话就是单点更新。由于时间比较紧,我们需要把所有的数压到一个int中去。

对任意x<=100 其因子个数情况如下:

int prime[]={ 2, 3, 5, 7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
int  dpos[]={28,25,23,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
//max num          7  4  2  2  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
//bit              3  3  2  2  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1
//tot bit  3+3+2+2+21*1=31
// 0000 0000 0000 0000 0000 0000 0000 0000
//    |   |  | |
//    2   3  5 7 

所以,可以用一个32位的int数字表示x对应的各因子数

#define _min(x,y) ((x)<(y)?(x):(y))
#define _max(x,y) ((x)>(y)?(x):(y))
inline int min(int x,int y){return _min(x&0x70000000,y&0x70000000)|_min(x&0x0e000000,y&0x0e000000)|_min(x&0x01800000,y&0x01800000)|_min(x&0x00600000,y&0x00600000)|((x&0x001fffff)&(y&0x001fffff));
}
inline int max(int x,int y){return _max(x&0x70000000,y&0x70000000)|_max(x&0x0e000000,y&0x0e000000)|_max(x&0x01800000,y&0x01800000)|_max(x&0x00600000,y&0x00600000)|((x&0x001fffff)|(y&0x001fffff));
}

自定义比较函数,即分别计算x与y的每个因子出现的最大与最小次数。

然后就是裸的单点更新,成段求最值的线段树了

001 #include<cstdio>
002  
003 const int maxn=444444;
004 int prime[]={ 2, 3, 5, 7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
005 int  dpos[]={28,25,23,21,20,19,18,17,16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
006 int a[]={1,2,4,8,16,32,64};
007 int b[]={1,3,9,27,81};
008 int c[]={1,5,25};
009 int d[]={1,7,49};
010  
011 #define lson l,mid,lrt
012 #define rson mid+1,r,rrt
013 #define mid ((l+r)>>1)
014 #define lrt rt<<1
015 #define rrt rt<<1|1
016  
017 int MAX[maxn],MIN[maxn];
018 inline int turn(int x){
019     int cnt,y=0;
020     for(int i=0;i<25&&x>1;i++){
021     for(cnt=0;x%prime[i]==0;x/=prime[i]) cnt++;
022     y|=cnt<<dpos[i];
023     }
024     return y;
025 }
026 inline int back(int x,int p)
027 {
028     long long y=1;
029     int k=x>>dpos[0];y=y*a[k]%p;x^=k<<dpos[0];
030     k=x>>dpos[1];y=y*b[k]%p;x^=k<<dpos[1];
031     k=x>>dpos[2];y=y*c[k]%p;x^=k<<dpos[2];
032     k=x>>dpos[3];y=y*d[k]%p;x^=k<<dpos[3];
033     for(int i=4;i<25;i++)
034     if(x&(1<<dpos[i])) y=y*prime[i]%p;
035     return y;
036 }
037 #define _min(x,y) ((x)<(y)?(x):(y))
038 #define _max(x,y) ((x)>(y)?(x):(y))
039 inline int min(int x,int y){
040     return _min(x&0x70000000,y&0x70000000)|_min(x&0x0e000000,y&0x0e000000)|_min(x&0x01800000,y&0x01800000)|_min(x&0x00600000,y&0x00600000)|((x&0x001fffff)&(y&0x001fffff));
041 }
042 inline int max(int x,int y){
043     return _max(x&0x70000000,y&0x70000000)|_max(x&0x0e000000,y&0x0e000000)|_max(x&0x01800000,y&0x01800000)|_max(x&0x00600000,y&0x00600000)|((x&0x001fffff)|(y&0x001fffff));
044 }
045  
046  
047 inline void pushup(int rt){
048     MAX[rt]=max(MAX[lrt],MAX[rrt]);
049     MIN[rt]=min(MIN[lrt],MIN[rrt]);
050 }
051 void build(int l,int r,int rt){
052     if(l==r){
053     int x;scanf("%d",&x);
054     MIN[rt]=MAX[rt]=turn(x);
055     return;
056     }
057     build(lson);build(rson);
058     pushup(rt);
059 }
060 void update(int k,int x,int l,int r,int rt){
061     if(l==r){
062     MAX[rt]=MIN[rt]=turn(x);
063     return;
064     }
065     if(k<=mid) update(k,x,lson);
066     else update(k,x,rson);
067     pushup(rt);
068 }
069 int query_max(int s,int t,int l,int r,int rt){
070     if(s<=l&&t>=r) return MAX[rt];
071     int ret=0;
072     if(s<=mid) ret=max(ret,query_max(s,t,lson));
073     if(t>mid)  ret=max(ret,query_max(s,t,rson));
074     return ret;
075 }
076 int query_min(int s,int t,int l,int r,int rt){
077     if(s<=l&&t>=r) return MIN[rt];
078     int ret=0x7fffffff;
079     if(s<=mid) ret=min(ret,query_min(s,t,lson));
080     if(t>mid)  ret=min(ret,query_min(s,t,rson));
081     return ret;
082 }
083 int main()
084 {
085     int n,q;
086     while(scanf("%d%d",&n,&q)!=EOF){
087     build(1,n,1);
088     char s[2];
089     while(q--){
090         scanf("%s",s);
091         if(s[0]=='C'){
092         int k,v;
093         scanf("%d%d",&k,&v);
094         update(k,v,1,n,1);
095         }
096         else if(s[0]=='L'){
097         int k1,k2,p;
098         scanf("%d%d%d",&k1,&k2,&p);
099         int x=query_max(k1,k2,1,n,1);
100         printf("%u\n",back(x,p));
101         }
102         else{
103         int k1,k2,p;
104         scanf("%d%d%d",&k1,&k2,&p);
105         int x=query_min(k1,k2,1,n,1);
106         printf("%u\n",back(x,p));
107         }
108     }
109     }
110     return 0;
111 }

参考:http://blog.csdn.net/wxfwxf328/article/details/7479874

HDU 3071-Gcd Lcm game-线段树+素因子分解-[解题报告]HOJ相关推荐

  1. 洛谷 P3373 【模板】线段树 2 解题报告

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...

  2. HDU 1166 敌兵布阵(线段树:点更新,区间求和)

    HDU 1166 敌兵布阵(线段树:点更新,区间求和) http://acm.hdu.edu.cn/showproblem.php?pid=1166 题意: 给你n个整数,然后给你多条命令,每条命令如 ...

  3. HDU 3016 Man Down (线段树+dp)

    HDU 3016 Man Down (线段树+dp) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Ja ...

  4. 2019CCPC网络赛 1002 HDU 6703(权值线段树)

    2019CCPC网络赛 1002 HDU 6703(权值线段树) 思路:用权值线段树存题目给的数据后,2操作就是求权值线段树中大于等于k的部分中,靠近左端点的第一个大于r的值(这个求出来的只是原序列中 ...

  5. HDU - 5381 The sum of gcd(莫队/线段树区间合并)

    题目链接:点击查看 题目大意:给出一个长度为 nnn 的序列,再给出 mmm 次询问,每次询问需要回答区间 [L,R][L,R][L,R] 内所有子区间的 gcdgcdgcd 之和.更具体的,对于询问 ...

  6. 2014多校第四场1006 || HDU 4902 Nice boat (线段树 区间更新)

    题目链接 题意 : 给你n个初值,然后进行两种操作,第一种操作是将(L,R)这一区间上所有的数变成x,第二种操作是将(L,R)这一区间上所有大于x的数a[i]变成gcd(x,a[i]).输出最后n个数 ...

  7. HDU 6070 Dirt Ratio(线段树、二分)

    http://acm.hdu.edu.cn/showproblem.php?pid=6070 题解 首先不难看出错误率是单调的,那么我们可以直接二分答案x,某个区间的错误率=区间数的种类cnt/区间长 ...

  8. hdu 5692 Snacks(dfs序+线段树区间更新)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692 解题思路:这道题是树节点的点权更新,而且涉及到子树,常用的思路是利用dfs序,用线段树来对区间进 ...

  9. HDU 6089 Rikka with Terrorist (线段树)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6089 题解 这波强行维护搞得我很懵逼... 扫描线,只考虑每个点能走到左上方(不包括正上方,但包括正左 ...

最新文章

  1. 上传文件大小的配置Webcong
  2. php实现文件夹管理器,php实现文件管理与基础功能操作
  3. Keras保存和载入训练好的模型和参数
  4. CentOs7安装apache以及遇到的问题
  5. Android安全笔记-进程间通信基本概念(intent、bundle、Parcelable、parcel)
  6. springboot2.0 fastjson 日期格式化不生效解决
  7. python爬取知乎live_Python爬虫从入门到放弃(十九)之 Scrapy爬取所有知乎用户信息(下)...
  8. 一招教你数据仓库如何高效批量导入与更新数据
  9. web项目中保存emoji到mysql数据库
  10. java jdk的作用_Java JDK环境配置及配置作用说明
  11. QQ输入法新功能设计文档
  12. 开4核后用哪个软件测试稳定性,测试CPU的稳定性的方法
  13. 陈强《高级计量经济学及stata应用》相关数据
  14. 360无线wifi路由器连接到服务器,把360无线路由器设置为二级路由器 | 192路由网...
  15. Tableau权限设置
  16. SOHO如何做外贸独立站?
  17. freeRTOS学习 — 消息邮箱
  18. php ffmpeg 转码mp4,PHP+FFMPEG实现将视频自动转码成H264标准Mp4文件
  19. un ange frappe a ma porte
  20. 3DMAX中旋转楼梯的做法

热门文章

  1. 手写字体识别用python实现_利用贝叶斯算法实现手写体识别(Python)
  2. BP神经网络算法基本原理,bp神经网络实例分析
  3. 在 Ubuntu 上安装 Budgie 桌面
  4. 卡西欧5800计算机隧道程序,卡西欧5800隧道放样程序
  5. 计算从前某个时间距离现在经过了多久时间
  6. 机器学习资源个人汇总
  7. 分享一个程序猿小白两年工作经验的职业之路
  8. 怎样将webp格式转换成jpg格式
  9. 从contiki中下载程序到TelosB节点
  10. win7优化设置_Win7旗舰版系统磁盘碎片整理程序几种打开方法