容斥原理。看完题唯一的想法就是暴力
后边的相关讨论里讲解的很详细,代码也是看的讲解这个题目的那人的,花了我60点头盾呢。。。。
对于容斥原理,我也仅限于用纸笔计算离散数学课本后边那种数据量极小的题目,却不会用代码来算。。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN = 100100;
int num[MAXN];
int val[MAXN];
int factors[MAXN];
int facLen;
long long S = 0;
void init(int n)
{
for(int i = 1; i <= n; ++i)
{
for(int j = 1; i*j <= n; ++j)
val[i] += num[i*j];
}
}
//维护val
void update(int index, int tval)
{
S -= num[index];
int m = sqrt(index);
for(int i = 1; i <= m; ++i)
{
if(index%i == 0)
{
if(i*i == index)
val[i] = val[i]-num[index] + tval;
else
{
val[index/i] = val[index/i] - num[index] + tval;
val[i] = val[i] - num[index] + tval;
}
}
}
num[index] = tval;
S += num[index];
}
//分解素因子
void getFactors(int nb)
{
int m = sqrt(nb);
facLen = 0;
for(int i = 2; i <= m; ++i)
{
if(nb%i == 0)
{
while(nb%i==0) nb /= i;
factors[facLen++] = i;
}
}
if(nb != 1) factors[facLen++] = nb;
}
//容斥
long long solve(int nb)
{
long long res = 0;
getFactors(nb);
int num;
int t;
int v;
for(int i = 1; i < (1<<facLen); ++i)
{
v = i;
t = 1;
num = 0;
for(int j = 0; j < facLen; ++j)
{
if(v&(1<<j))
{
t *= factors[j];
num++;
}
}
if(num&1)
res += val[t];
else
res -= val[t];
}
return res;
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
int n,q;
cin >> n >> q;
for(int i = 1; i <= n; ++i)
{
cin >> num[i];
S += num[i];
}
init(n);
int a,b,index;
while(q--)
{
cin >> a;
if(a == 1)
{
cin >> index >> b;
update(index,b);
}
else
{
cin >> b;
cout << S - solve(b) << endl;
}
}
return 0;
}