您的位置:首页 > 产品设计 > UI/UE

UESTC 87 Easy Problem With Numbers 线段树区间更新 逆元 分解质因数

2015-10-09 16:12 429 查看
UESTC 87 Easy Problem With Numbers

题意:

题意非常简单,给定一个序列 和 M 三种操作

区间内所有元素乘以x

区间内所有元素除以x

查询区间所有元素积取余M

思路:

线段树

问题的关键是区间内所有元素除以x这个操作.

因为要取模,所以不能直接搞.

怎么办?首先我们想到逆元

但是

定理:a存在模p的乘法逆元的充要条件是gcd(a,p) = 1

于是想到了以M的素因子 分解x 最后剩下的数px肯定满足gcd(px,M) = 1

这样我们要维护的东西变成了区间内每个素因子的个数和 与 与M互质的那个数的逆元

#include <bits/stdc++.h>
#define lson num<<1
#define rson num<<1|1
#define gl l,m,lson
#define gr m+1,r,rson
#define PARA int l=1,int r=n,int num=1
#define CLR(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long LL;
const int MAXN = 1e4+100;
int n;
LL MOD;

template <class T>
inline void scan_d(T &ret) {
char c; ret=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
}
void ex_gcd(LL a, LL b, LL &x, LL &y)
{
if(b == 0)
{
x = 1;
y = 0;
return;
}
ex_gcd(b, a % b, x, y);
LL tmp = x;
x = y;
y = tmp - (a / b) * y;
}
LL inv(LL v)
{
LL x,y;
ex_gcd(v,MOD,x,y);
x%=MOD;
while(x<0) x+=MOD;
return x;
}

LL mod(LL a, LL b)
{
if(b < 0) return 0;
LL ret = 1;
a %= MOD;
for (; b; b >>= 1, a = (a * a) % MOD)
if (b & 1)
ret = (ret * a) % MOD;
return ret;
}

struct Factor
{
LL fac[12];
LL ret[12];
int cnt;
void init(LL v)
{
cnt=0;
for(LL i=2;i*i<=v;i++)
{
if(v%i==0)
fac[cnt++]=i;
for(;v%i==0;v/=i);
}
if(v!=1)    fac[cnt++]=v;
}
void find(LL &v,int f)
{
for(int i=0;i<cnt;i++)
{
ret[i]=0;
for(;v&&v%fac[i]==0;v/=fac[i])
ret[i]=ret[i]+f;
}
}
}pf;

struct SegTree
{
struct Node
{
LL l,r;
LL fac[12],tag[12];
LL v,tv;
bool has=0;
void init(LL a,LL b)
{
l=a,r=b;
v=1;
tv=1;
CLR(fac);
CLR(tag);
has=0;
}
void mark(LL *a,LL b)
{
tv*=b;
tv%=MOD;
for(int i=0;i<pf.cnt;i++)
{
tag[i]+=a[i];
fac[i]+=a[i]*(r-l+1);
}
v=v*mod(b,r-l+1);
v%=MOD;
has=1;
}
LL count()
{
LL ret=v%MOD;
for(int i=0;i<pf.cnt;i++)
ret=ret*mod(pf.fac[i],fac[i]),ret%=MOD;
return ret;
}
void show()
{
printf("(%lld,%lld):%lld\n",l,r,count());
printf("v:%lld\n",v);
for(int i=0;i<pf.cnt;i++)
printf(" %d",fac[i]);
puts("");
printf("tv:%lld\n",tv);
for(int i=0;i<pf.cnt;i++)
printf(" %d",tag[i]);
puts("\n");
}
}st[MAXN<<2];
void pushUp(int num)
{
for(int i=0;i<pf.cnt;i++)
st[num].fac[i]=st[lson].fac[i]+st[rson].fac[i];
st[num].v=st[lson].v*st[rson].v%MOD;
}
void pushDown(int num)
{
LL l=st[num].l,r=st[num].r;
if(l!=r)
{
if(st[num].has)
{
st[lson].mark(st[num].tag,st[num].tv);
st[rson].mark(st[num].tag,st[num].tv);
pushUp(num);
CLR(st[num].tag);
st[num].tv=1;
}
pushUp(num);
}
st[num].has=0;
}
void init(PARA)
{
int m=l+r>>1;
st[num].init(l,r);
if(l==r)
{
LL v;
scan_d(v),pf.find(v,1);
st[num].mark(pf.ret,v);
}
else init(gl),init(gr),pushUp(num);
}
void update(int a,int b,LL v,PARA)
{
pushDown(num);
if(a<=l&&r<=b)
st[num].mark(pf.ret,v);
else
{
int m=l+r>>1;
if(b<=m)
update(a,b,v,gl);
else if(a>m)
update(a,b,v,gr);
else
update(a,b,v,gl),update(a,b,v,gr);
pushUp(num);
}
}
LL query(int a,int b,PARA)
{
pushDown(num);
if(a<=l&&r<=b)
return st[num].count();
else
{
int m=l+r>>1;
LL ret;
if(b<=m)
ret=query(a,b,gl);
else if(a>m)
ret=query(a,b,gr);
else
ret=query(a,b,gl)*query(a,b,gr);
pushUp(num);
return ret%MOD;
}
}
void show(PARA)
{
int m=l+r>>1;
st[num].show();
if(l!=r)
show(gl),show(gr);
}
}soul;

bool DEBUG=0;
void debug()
{
puts("______");
soul.show();
puts("______");
}

int main()
{
if(DEBUG) freopen("v3.txt","w",stdout);
int T,cas=1;
scan_d(T);
while(T--)
{
scan_d(n);
scan_d(MOD);
pf.init(MOD);
soul.init();
int m;
scan_d(m);
printf("Case #%d:\n",cas++);
if(DEBUG)   debug();
while(m--)
{
char s[5];
scanf("%s",s);
LL a,b,c;
scan_d(a);
scan_d(b);
if(s[0]=='Q')
printf("%lld\n",soul.query(a,b));
else
{
scan_d(c);
int f;
if(s[0]=='M')
pf.find(c,1);
else
pf.find(c,-1),c=inv(c);
soul.update(a,b,c);
}
if(DEBUG)   debug();
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: