Codeforces 1493D GCD of an Array stl维护
作者:互联网
文章目录
题目地址
题意
给出一个序列,每次在一个位置上乘一个数,并询问整个数列的 g c d gcd gcd.
题解
所有数字都在
2
×
1
0
5
2\times10^5
2×105之内,我们先筛素数,把每一个数的质因子的个数存放到
v
e
c
t
o
r
vector
vector里.
用
n
n
n个
m
a
p
map
map存储每个数的各个素因子的个数有多少个.
如果一个质数作为因子出现在所有数中,我们就把它放到台面上,用一个
m
u
l
t
i
s
e
t
multiset
multiset存储每一个数的这个质因子的个数,取
b
e
g
i
n
begin
begin即为最小值,用快速幂乘起来即可.
#pragma GCC optimize("inline","Ofast","no-stack-protector")
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int yuzu=2e5,mod=1e9+7;
typedef int fuko[yuzu|10];
fuko val,id,b,cnt,vis,vid;
using pii=pair<int,int>;
vector<pii> g[yuzu|10];
multiset<int> s[yuzu|10];
map<int,int> a[yuzu|10];
ll kasumi(ll a,ll b) {
ll zw=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) zw=zw*a%mod;
return zw;
}
int main() {
int n,q,i,j,len=0;
for (i=2;i<=yuzu;++i) {
if (!vis[i]) {
for (j=i;j<=yuzu;j+=i) {
int tmp=0,tmp2=j;
vis[j]=1;
for (;tmp2%i==0;++tmp) tmp2/=i;
g[j].push_back(pii(i,tmp)); // g[j]中的每一个pair的first是j的这个质因子,second是这个数的质因子i的个数.
}
}
}
read(n),read(q);
for (i=1;i<=n;++i) {
read(b[i]);
for (auto p:g[b[i]]) {
++cnt[p.first];
a[i][p.first]=p.second;
if (cnt[p.first]==n) { // 含有这个质因数的数的个数达到n,我们需要把这个质因数搬上台面,给他一个编号.
++len;
for (j=1;j<=n;++j) s[len].insert(a[j][p.first]);
val[len]=p.first;
vid[p.first]=len;
}
}
}
for (;q--;) {
int pos,x;
read(pos),read(x);
for (auto p:g[x]) {
if (a[pos].find(p.first)==a[pos].end()) { //这个位置没有这个质因子.
++cnt[p.first];
a[pos][p.first]=p.second;
if (cnt[p.first]==n) {
++len;
for (j=1;j<=n;++j) s[len].insert(a[j][p.first]);
val[len]=p.first;
vid[p.first]=len;
} //和输入的时候一样的操作.
} else {
if (vid[p.first]) { // 这个质数是有头有脸在所有数中都出现的质数.
s[vid[p.first]].erase(s[vid[p.first]].find(a[pos][p.first])); // 删掉.
a[pos][p.first]+=p.second; // 增加.
s[vid[p.first]].insert(a[pos][p.first]); //再加回来.
} else {
a[pos][p.first]+=p.second;
}
}
}
ll zw=1;
for (i=1;i<=len;++i) {
zw=zw*kasumi(val[i],*s[i].begin())%mod; // 最终答案为所有质因子个数乘方之和.
}
printf("%lld\n",zw);
}
}
这个稳健的代码TLE了.为什么会出问题呢?
问题就在
n
=
1
n=1
n=1的时候,每一次相乘都会使一个质因子被搬上台面,因此
l
e
n
len
len的大小为质数的总数,则询问的复杂度达到
O
(
n
q
)
O(nq)
O(nq),爆炸.
解决这个问题的方法就是不要每次遍历所有
s
e
t
set
set,而是直接在操作中对
a
n
s
ans
ans进行维护.
修改得代码
#include<bits/stdc++.h> //Ithea Myse Valgulious
using namespace std;
const int yuzu=2e5,mod=1e9+7;
typedef int fuko[yuzu|10];
fuko val,id,b,cnt,vis,vid;
using pii=pair<int,int>;
vector<pii> g[yuzu|10];
multiset<int> s[yuzu|10];
map<int,int> a[yuzu|10];
ll kasumi(ll a,ll b=mod-2) {
ll zw=1;
for (;b;b>>=1,a=a*a%mod) if (b&1) zw=zw*a%mod;
return zw;
}
int main() {
int n,q,i,j,len=0;
for (i=2;i<=yuzu;++i) {
if (!vis[i]) {
for (j=i;j<=yuzu;j+=i) {
int tmp=0,tmp2=j;
vis[j]=1;
for (;tmp2%i==0;++tmp) tmp2/=i;
g[j].push_back(pii(i,tmp));
}
}
}
ll zw=1;
read(n),read(q);
for (i=1;i<=n;++i) {
read(b[i]);
for (auto p:g[b[i]]) {
++cnt[p.first];
a[i][p.first]=p.second;
if (cnt[p.first]==n) {
++len;
for (j=1;j<=n;++j) s[len].insert(a[j][p.first]);
val[len]=p.first;
vid[p.first]=len;
zw=zw*kasumi(val[len],*s[len].begin())%mod;
}
}
}
for (;q--;) {
int pos,x;
read(pos),read(x);
for (auto p:g[x]) {
if (a[pos].find(p.first)==a[pos].end()) {
++cnt[p.first];
a[pos][p.first]=p.second;
if (cnt[p.first]==n) {
++len;
for (j=1;j<=n;++j) s[len].insert(a[j][p.first]);
val[len]=p.first;
vid[p.first]=len;
zw=zw*kasumi(val[len],*s[len].begin())%mod;
}
} else {
int nid=vid[p.first];
if (nid) {
zw=zw*kasumi(kasumi(p.first,*s[nid].begin()))%mod;
s[nid].erase(s[nid].find(a[pos][p.first]));
a[pos][p.first]+=p.second;
s[nid].insert(a[pos][p.first]);
zw=zw*kasumi(p.first,*s[nid].begin())%mod;
} else {
a[pos][p.first]+=p.second;
}
}
}
printf("%lld\n",zw);
}
}
成功AC.
谢谢大家.
标签:1493D,GCD,stl,ll,pos,int,read,zw,first 来源: https://blog.csdn.net/qq_31908675/article/details/114492677