『HDU 5970』最大公约数

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5970

题意:(中文题,不用我说了吧.)
『HDU 5970』最大公约数_第1张图片

分析:
当时在比赛的时候并没有做出来,主要是时间不够,有点分心在其他题上,然后就水了.其实看到这种题,第一想法不用想太复杂,可能有暴力的方法,找规律!
看看数据范围
n <= 666,666,666, m <= 666, p <= 666,666,666
突破口必然在m上,那怎么用呢?
不可能暴力gcd和T的,这样必然超时,我们知道gcd(a,b)=gcd(b,a%b)
那又怎么样呢?那么给你一个提示,例如gcd(5,9)=gcd(16,9)
手写一下,你就发现确实是这样啊~!
不仅如此,f(5,9)=f(16,9)
那么我们就知道,如果以m为基数的话,那么对于所有的n,莫非就余0,余1,余2…余m-1
我们就可以这样做,然后就可以统计同余的有多少个,然后看一下规律,然后一大片的求,
就能在m^2的时间求出答案了…
别住,这个规律还是有问题啊.
它有向下取整,不可能把个i什么的拆出来,就必须一个个才行.就是**(i*j)/f(i,j)**.
那就会出现多1,少1的情况…因为取整问题…

那么我们先暴力一段序列.看看数据有什么问题.
例如 9余5的所有数的f(i,j)
『HDU 5970』最大公约数_第2张图片
这明显有规律啊,循环节啊…

这下就懵逼了,循环节该怎么搞啊?
他们的差值又不一样…,这是个好问题,但是既然是循环节,肯定等差..

这里写图片描述
我也写了很久,然后我灵感来的猜出来的.
除去第一个f(y,m)=11;
他的差值循环节就是c
然后 d=c(f(y,m)=11)(代表c倍的,余数y和m的f).*
以上是我找到的规律,为什么是这样我就不太懂了,我也想了很久.
只要我们求出 **(31+51+72+92)**这段的初值,就可以用等差数列求循环节一整段
然后就是细节的处理了.

我的程序是卡过这题的,我也不知道为什么那么慢
算法复杂度在O(m^2*c) 我试过**On(m^2*2c)**都不行,因为这个循环节规律就是逼我在这种情况下找出来的.

/* Author:GavinjouElephant
 * Title:
 * Number:
 * main meanning:
 *
 *
 *
 */


#include 
using namespace std;
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//#include
//#include 
//#include 
//#include 
#define MaxN 0x7fffffff
#define MinN -0x7fffffff
#define lson 2*k
#define rson 2*k+1
typedef long long ll;
const ll INF=0x3f3f3f3f;
const ll maxn=700;
ll Scan()//读入整数外挂.
{
    ll res = 0, ch, flag = 0;

    if((ch = getchar()) == '-')             //判断正负
        flag = 1;

    else if(ch >= '0' && ch <= '9')           //得到完整的数
        res = ch - '0';
    while((ch = getchar()) >= '0' && ch <= '9' )
        res = res * 10 + ch - '0';
    return flag ? -res : res;
}
void Out(ll a)    //输出外挂
{
    if(a>9)
        Out(a/10);
    putchar(a%10+'0');
}
ll Fc[maxn][maxn];
ll Fcx[maxn][maxn];


void  f(ll x,ll y)
{
    ll tx=x,ty=y;
    ll c=0;
    while(y>0)
    {
        c+=1;
        ll t=x%y;
        x=y;
        y=t;
    }

    Fc[tx][ty]=c;
    Fcx[tx][ty]=c*x*x;

}

void init()
{

    for(ll j=1; j<=666; j++)
    {
        for(ll i=0; i<=j; i++)
        {
            f(i,j);
        }
    }
}


ll cas(ll x,ll y)
{
    return (x*y)/Fcx[x%y][y];
}

int T;
ll n,m,p;
ll top;
ll xhj[5000];
ll Sum[5000];

int main()
{
#ifndef ONLINE_JUDGE
    freopen("coco.txt","r",stdin);
    freopen("lala.txt","w",stdout);
#endif

    init();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%I64d%I64d%I64d",&n,&m,&p);
        ll ans=0;
        ll d;

        for(ll j=1; j<=m; j++)
        {
            for(ll y=0; y找循环节
                    if(num==0) continue;

                    ll t=(num-1)/Fc[y][j];
                    ll tt=(num-1)%Fc[y][j];
                    ll s=cas(y,j);

                    ans=(ans+s)%p;

                    ll ss=0;
                    ll sum=0;
                    top=0;

                    int i=y+j;
                    for(top=0;top

你可能感兴趣的:(『数据结构与算法』)