[LA 6601 Teaching Hazard] 数学

题目

https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=599&page=show_problem&problem=4612

分析

其实思路就是枚举结尾0的个数,从x开始向上枚举,n只有10万,加上保证解在5 * 10^18之内,因此枚举数量不是很多。

当枚举个数为i个0时,枚举n的质因数,对每个质因数p算出最大的r使得进制b(b % p ^ r == 0 && b % (p ^ (r + 1)) != 0) 末尾有大于等于i个0,记为s

同时算出末尾大于等于i+1个0的个数t,对每个质因数累乘(s - t)。结果记为a。最后答案累加C(a,2)。

代码

#include<cstring>
#include<string>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<vector>
#include<algorithm>
#include<queue>
using namespace std;
#define ll long long
#define pf printf
#define sf scanf
#define Fill(a,b) memset(a,b,sizeof(a))
const int N = 100000;
bool v[N + 10];
ll s[N + 10],t[N + 10];
int p[N + 10];
int tot,n;
int x;
int sum[N + 10];
void get_prime()
{
    Fill(v,0);
    tot = 0;
    for (int i = 2; i <= N; i++)
        if (!v[i])
        {
            p[++tot] = i;
            for (int j = i * 2; j <= N; j += i) v[j] = 1;
        }
}
inline int solve(int x,int y)
{
   /* ll sum = 0;ll tp = n;
    while (tp > 0ll)
    {
        sum = sum + tp / x;
        tp = tp / x;
    }
    return sum / y;*/
    return sum[x] / y;
}
inline int get(int x)
{
    int sum = 0;
    int tp = n;
    while (tp > 0)
    {
        sum = sum + tp / x;
        tp = tp / x;
    }
    return sum;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","r",stdout);
    get_prime(); //cout<<tot<<endl;
    int cas = 0;
    while (sf("%d%d",&n,&x) != EOF)
    {
        //cas++; pf("%d\n",cas);
        for (int i = 2; i <= n; i++) sum[i] = get(i);
        if (n == 0 && x == 0) break;
        ll ans = 0;
        while(1)
        {
            int lim = tot;
            for (int i = 1; i <= tot; i++)
            {
                s[i] = solve(p[i],x);
                t[i] = solve(p[i],x + 1);
                if (s[i] == 0)
                {
                    lim = i - 1;
                    break;
                }
            }
            if (lim == 0) break;
            //break;
            ll tmp1 = 1,tmp2 = 1;
            for (int i = 1; i <= lim; i++) tmp1 = tmp1 * (s[i] + 1),tmp2 = tmp2 * (t[i] + 1);
           // for (int i = 1; i <= lim; i++) cout<<s[i]<<endl;
            tmp1 = tmp1 - tmp2;
            ans = ans + (tmp1 * (tmp1 - 1)) / 2;
            x++;
        }
        pf("%lld\n",ans);
    }
    return 0;
}


你可能感兴趣的:([LA 6601 Teaching Hazard] 数学)