wannafly 27 D 巧妙求取约数
链接:https://www.nowcoder.com/acm/contest/215/D
来源:牛客网
题目描述
“我不知道你在说什么,因为我只是个pupil。”--绿魔法师
n次操作,每次操作给出x,k,p,执行以下操作:
1、在S中加入x。
2、输出
输入描述:
所有输入的数都是小于1e5+1的正整数。
输出描述:
输出对应的结果
示例1
输出
复制4 2 1
题意 : 每次增加一个数,求新增加的数同前面每个数的gcd 的 k 次幂再对 p 取模,将答案累加
思路分析 :
考虑每次增加一个数时,需要找到同前面每个数字的 gcd, 本质上的 gcd 就是当前数的约数中的某一个
因此每插入一个新的元素时,就是相当于插入了当前这个数的所有的约数,从最大的约数开始插入,并且每次检索前面有此约数的数有多少个即可
复杂度 n*w*w ,w 为这个数的约数个数,但实际在 w^2 枚举因数时的复杂度是不够 w^2 的
代码示例 :
#define ll long long
const ll maxn = 1e5+5;
ll n;
ll x, k, p;
vector<ll>ve[maxn];
inline ll read() {
ll x = 0, f = 1; register char ch = getchar();
while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x*f;
}
inline void init() {
for(ll i = 1; i <= 100000; i++){
for(ll j = i; j <= 100000; j += i){
ve[j].push_back(i);
}
}
}
inline ll qw(ll x, ll cnt){
ll res = 1;
while(cnt){
if (cnt&1) res *= x;
res %= p;
x *= x;
x %= p;
cnt >>= 1;
}
return res;
}
ll cnt[maxn], del[maxn];
ll pp[maxn], pt[maxn];
inline void solve() {
for(ll i = 0; i < ve[x].size(); i++) cnt[ve[x][i]]++;
ll ans = 0;
ll c = 0;
for(ll i = ve[x].size()-1; i >= 0; i--){
ll num = ve[x][i];
if (cnt[num] <= del[num]) continue;
ans += (cnt[num]-del[num])*qw(num, k)%p;
ans %= p;
for(ll j = 0; j < ve[num].size(); j++){
ll f = ve[num][j];
del[f] += (cnt[num]-del[num]);
}
}
for(int i = 0; i < ve[x].size(); i++) del[ve[x][i]] = 0;
printf("%lld\n", ans);
}
int main() {
init();
cin >> n;
for(ll i = 1; i <= n; i++){
x = read(), k = read(), p = read();
solve();
}
return 0;
}
东北日出西边雨 道是无情却有情

浙公网安备 33010602011771号