codeforces 594 D. REQ (树状数组+欧拉函数+逆元)
题意:给出n个数,q个查询,每组一个区间,询问区间中所有数的乘积的欧拉函数9+7的答案是多少。
思路:这道题需要一点欧拉函数的知识。
phi(n)是欧拉函数,意义为小于等于n并且与n互质的数的个数。
To calculate the answer on every query let's use the formula
 , where _p_1, p_2, ..., p__k — all prime numbers which divided_n.
, where _p_1, p_2, ..., p__k — all prime numbers which divided_n.
如果知道欧拉函数的这个公式。。。那么这道题就成了水题。。。。
考虑两个数a,b的欧拉函数。
一开始考虑也许有什么性质。。。查了下欧拉函数的wiki 欧拉函数_维基百科 欧拉函数是积性函数(但不是完全积性函数。。因此必须phi(ab) =phi(a)*phi(b)成立当且仅当gcd(a,b)==1)
然而这里并不一定满足互质的条件。。。
再想一下。。。发现完全没必要由phi(a)和phi(b)得到phi(a*b)
直接把a*b看成一个数就好了。。。。
后面质因子乘积部分只需要把两部分的并在一起就好了。。。
所以根据上面欧拉函数的公式。。。答案分为两部分。。。
一部分是区间中所有数的乘积。。。
一部分是区间中所有数的不相同的素因子的p-1/p形式的乘积。。。
第一部分预处理前缀积即可。。。由于有%运算。。。所以除的时候需要计算逆元。。。
第二部分的做法同spoj_dquery解题报告
也是离线处理,把询问按照区间右端点排序升序排列,然后lst数组记录上次该数出现的位置。。。用bit维护一个从1到某个数的乘积。。。在撤销的时候同样需要逆元。。。
还要注意。。。太长的式子一定要分开写。。。。
因为写错括号顺序调了半天orz...
  1/* ***********************************************
  2Author :111qqz
  3Created Time :Thu 22 Sep 2016 02:07:39 PM CST
  4File Name :code/cf/problem/594D.cpp
  5************************************************ */
  6#include <cstdio>
  7#include <cstring>
  8#include <iostream>
  9#include <algorithm>
 10#include <vector>
 11#include <queue>
 12#include <set>
 13#include <map>
 14#include <string>
 15#include <cmath>
 16#include <cstdlib>
 17#include <ctime>
 18#define fst first
 19#define sec second
 20#define lson l,m,rt<<1
 21#define rson m+1,r,rt<<1|1
 22#define ms(a,x) memset(a,x,sizeof(a))
 23typedef long long LL;
 24#define pi pair < int ,int >
 25#define MP make_pair
 26using namespace std;
 27const double eps = 1E-8;
 28const int dx4[4]={1,0,0,-1};
 29const int dy4[4]={0,-1,1,0};
 30const int inf = 0x3f3f3f3f;
 31const int N=2E5+7;
 32const int M=1E6+7;
 33const LL MOD = 1E9+7;
 34struct node
 35{
 36    int l,r;
 37    int id;
 38    bool operator < (node b)const
 39    {
 40	return r<b.r;
 41    }
 42}q[N];
 43LL a[N],pre[N];
 44int lst[M];
 45int n,Q;
 46LL ksm(LL a,LL b)
 47{
 48    LL res = 1LL;
 49    while (b>0LL)
 50    {
 51	if (b%2)
 52	    res = (res*a)%MOD;
 53	b = b>>1LL;
 54	a = (a*a)%MOD;
 55    }
 56    return res;
 57}
 58LL get_inv(LL x){
 59    return ksm(x,MOD-2);
 60}
 61bool vis[M];
 62vector <int>factor[M];
 63void init( ) //预处理1到1E6的每个数的质因子
 64{
 65    ms(vis,false);
 66    for ( int i = 2 ; i < M ; i++) 
 67	if (!vis[i])
 68	    for ( int j = i ; j < M ; j+=i)
 69		vis[j] = true,factor[j].push_back(i);
 70}
 71LL t[M];
 72int lowbit( int x) 
 73{
 74    return x&(-x);
 75}
 76void update( int x,LL delta)
 77{
 78    for ( int i = x ; i <= n ; i+=lowbit(i) )
 79	t[i] = (t[i] * delta)%MOD;
 80}
 81LL get_mul( int x)
 82{
 83    LL res = 1LL;
 84    for ( int i = x ; i >= 1 ; i-=lowbit(i))
 85	res = (res * t[i])%MOD;
 86    return res;
 87}
 88LL ans[N];
 89int main()
 90{
 91	#ifndef  ONLINE_JUDGE 
 92	freopen("code/in.txt","r",stdin);
 93  #endif
 94	init();
 95	ms(lst,0);
 96	scanf("%d",&n);
 97	for ( int i = 1 ;  i < M ; i++) t[i] = 1LL; //bit的初始化。。由于是乘积。。所以初始化为1.
 98	pre[0]=1LL;
 99	for ( int i = 1 ; i <= n ; i++) scanf("%lld",a+i),pre[i] = (pre[i-1]*a[i])%MOD;
100	scanf("%d",&Q);
101	for ( int i = 1 ; i <= Q ; i++) scanf("%d%d",&q[i].l,&q[i].r),q[i].id = i;
102	sort(q+1,q+Q+1);
103	int cur = 1;
104	for ( int i = 1 ; i <= Q ; i++)
105	{
106	    for  ( ; cur <= q[i].r ; cur++)
107	    {
108		int siz = factor[a[cur]].size();
109		for ( int j = 0 ; j < siz;  j++)
110		{
111		    int val = factor[a[cur]][j];
112		    if (lst[val])
113		    {
114			update(lst[val],val);
115			update(lst[val],get_inv(val-1));
116		    }
117		    update(cur,val-1);
118		    update(cur,get_inv(val));
119		    lst[val] = cur;
120		}
121	    }
122	    LL ans1 = get_mul(q[i].r)*get_inv(get_mul(q[i].l-1))%MOD;
123	    LL ans2 = pre[q[i].r]*get_inv(pre[q[i].l-1])%MOD;
124	    ans[q[i].id] = (ans1*ans2)%MOD;
125	    //mgj....这种这么长的一堆括号的式子分开写会死啊。。。。。。有毒。
126	    //ans[q[i].id] = (( get_mul(q[i].r)*get_inv(get_mul(q[i].l-1))%MOD ) * ( pre[q[i].r] * get_inv( pre[q[i].l-1] )%MOD ) )%MOD;
127	}
128	for ( int i = 1 ; i <= Q ; i ++) printf("%lld\n",ans[i]);
129  #ifndef ONLINE_JUDGE  
130  fclose(stdin);
131  #endif
132    return 0;
133}