C. Strange Function「思维 + 数论」

C. Strange Function

题目描述:

定义f(i)为最小的不能被 i 整除的正整数

∑ i = 1 n f ( i ) \sum_{i=1}^{n}f(i) i=1nf(i),1<=n<=1e16

思路:

打表发现根本找不到规律

暴力算肯定不行,毕竟n巨大

这个时候就该想想在n这么大的情况下不能暴力,也没有规律该怎么办

对于f(i) = x,我们分析一下会发现,因为 x 是最小的不能被 i 整除的最小正数,就说明其实 i 能整除 1 到 i - 1中的任何一个,也就是能整除lcm(1, 2, ……, x-1),但是绝对不能整除 x ,也就是说不能整除lcm(1, 2, ……, x),可以发现其实 x 的值不会很大,不到100,那我们就需要一个可以快速的统计出 n 个数中对于每个 x 满足 f(i) = x 的 i 的数量的方法就可以解决问题,根据上面写的两个lcm可以做一个容斥,f(i) = x的个数其实就等于 n u m = n / ( l c m ( 1 , 2 , 3 … … x − 1 ) ) − n / ( l c m ( 1 , 2 , 3 … … , x ) ) num = n / (lcm(1,2,3……x-1)) - n/(lcm(1,2,3……,x)) num=n/(lcm(1,2,3x1))n/(lcm(1,2,3,x)),而这个x产生的贡献就是x * num,而当lcm大于n的时候就不会再产生ans的贡献了就可以直接输出

总结:

当数据范围巨大的时候,考虑能否进行数论分块,分别计算每个块的答案

/*
Work by: Chelsea
Problem: 不知名屑题
Knowledge: 垃圾算法
Time: O(能过)
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//#include
using namespace std;

//#pragma GCC optimize("Ofast")
//#pragma GCC target("fma,sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
//#pragma GCC optimize("unroll-loops")

#define eps 1e-8
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#define NMAX 1000 + 50
#define ls p<<1
#define rs p<<1|1
#define mod 1000000007
#define lowbit(x) (x & (-x))
#define sz(s) (int)(s).size()
#define sd(n) scanf("%d",&n)
#define sdd(n,m) scanf("%d %d",&n,&m)
#define sl(n) scanf("%lld",&n)
#define sll(n,m) scanf("%lld %lld",&n,&m)
#define pd(n) printf("%d\n", (n))
#define pdd(n,m) printf("%d %d\n",n, m)
#define sddd(n,m,z) scanf("%d %d %d",&n,&m,&z)
#define slll(n,m,z) scanf("%lld %lld %lld",&n,&m,&z)
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define mem(a,b) memset((a),(b),sizeof(a))
#define m_p(a,b) make_pair(a, b)
typedef  long long ll;
typedef pair <int,int> pii;
typedef unsigned long long ull;
//不开longlong见祖宗!
inline int IntRead(){char ch = getchar();int s = 0, w = 1;while(ch < '0' || ch > '9'){if(ch == '-') w = -1;ch = getchar();}while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0';ch = getchar();}return s * w;}

//不改范围见祖宗!!!
#define MAX 1000000 + 50
ll n, m, k;
int x, y, z;
ll a, b, c;
string s, t;

ll gcd(ll a, ll b){
    if(b) return gcd(b, a % b);
    else return a;
}
ll lcm(ll a, ll b){
    return a / gcd(a, b) * b;
}

void work(){
    cin>>n;
    ll p = 1;
    ll ans = 0;
    for(ll i = 2;; ++i){
        ans = ans + (i * (n / p - n / lcm(p, i)) % mod) % mod;
        ans %= mod;
        p = lcm(p, i);
        if(p > n)break;
    }
    cout<<ans<<endl;
}

int main(){
    io;
    int tt;cin>>tt;
    for(int _t = 1; _t <= tt; ++_t){
//        printf("Case #%d: ", _t);
        work();
    }
    return 0;
}

你可能感兴趣的:(数论分块,lcm,cf,思维)