Sum of the Line(ICPC2017 Urumqi)

https://www.jisuanke.com/contest/1409/challenges

题目描述

Consider a triangle of integers, denoted by T. The value at (r, c) is denoted by Tr,c , where 1 ≤ r and 1 ≤ c ≤ r. If the greatest common divisor of r and c is exactly 1, Tr,c = c, or 0 otherwise.
Now, we have another triangle of integers, denoted by S. The value at (r, c) is denoted by S r,c , where 1 ≤ r and 1 ≤ c ≤ r. S r,c is defined as the summation    
Here comes your turn. For given positive integer k, you need to calculate the summation of elements in k-th row of the triangle S.

输入

The first line of input contains an integer t (1 ≤ t ≤ 10000) which is the number of test cases.
Each test case includes a single line with an integer k described as above satisfying 2 ≤ k ≤ 10^8 .

输出

For each case, calculate the summation of elements in the k-th row of S, and output the remainder when it divided
by 998244353.

样例输入

2
2
3

样例输出

1
5


题意:对于gcd(i,k) == 1,则S(i,k) = i,否则为0,求S = sigma(S(i,k)^2)

题解:
如果没有gcd(i,k)这个限制,则答案就为signa(i^2) 即sigma(i^2) = n*(n+1)*(2*n+1)/6
gcd(i,k) != 1,说明i 与 k 存在共同的因子(除1外),对于n(<=1e8)的最多的素因子不超过10个,对因子进行容斥
可以表示为:|U| - |A∪B∪C∪....∪Z| ,A ,B ,...., Z 分别表示为能被某个素数整除的

首先将k中素因子筛选出来,用唯一分解定理,然后对这些因子进行容斥,可以dfs,也可以用二进制 (0,1表示取或不取,但必须保证至少取一次)

AC code:
#include <iostream>
#include <cstdio>
using namespace std;
const int MAXN = 10000000;
const int mod = 998244353;
typedef long long ll;

ll fast_pow(ll a,ll n)
{
    ll ans = 1;
    while(n)
    {
        if(n&1) ans = (ans * a)%mod;
        a = (a * a)%mod;
        n >>= 1;
    }
    return ans;
}
const ll six = fast_pow(6,mod-2);

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int tot = 0;
        ll n,k;
        scanf("%lld",&k);
        n = k;
        int prime[100];
        for(int i = 2;i * i <= n;i++)
        {
            if(n % i == 0)
            {
                prime[tot++] = i;
                while(n % i == 0)   n /= i;
            }
        }
        if(n != 1) prime[tot++] = n;
        ll ans = k*(k+1)%mod*(2*k+1)%mod*six%mod;
        for(int i = 1;i < (1<<tot);i++)
        {
            n = i;
            int pos = tot - 1,cnt = 0;
            ll ant = 1;
            while(n)
            {
                if(n&1) ant *= prime[pos],cnt++;
                pos--;
                n >>= 1;
            }
            ll m = k/ant;
            if(cnt&1)
                ans = (ans - ant*ant%mod*m%mod*(m + 1)%mod*(2*m + 1)%mod*six%mod + mod)%mod;
            else
                ans = (ans + ant*ant%mod*m%mod*(m + 1)%mod*(2*m + 1)%mod*six%mod)%mod;
        }
        printf("%lld\n",ans);
    }
}

 






posted @ 2018-08-22 10:01  jadelemon  阅读(172)  评论(0编辑  收藏  举报