zoukankan      html  css  js  c++  java
  • Comet OJ

    传送门

    题意:
    求最小的(x),满足(frac{x(x+1)}{2}\% n=0,nleq 10^{12})
    多组数据,(Tleq 100)

    思路:

    • 直接考虑模运算似乎涉及到二次剩余什么的,但比较复杂。
    • 注意到比较特殊的就是,最后结果为(0),那么我们就考虑将问题转化为整除。
    • 所以式子等价于(n|frac{x(x+1)}{2})(2n|x(x+1))
    • 注意到(n)的范围,那么我们能((Osqrt{n}))来枚举(p,q),满足(pq=2n)
    • 那么就有(pq|x(x+1)),不妨设(x=qb,x+1=pa),那么就有(pa-qb=1),现在就相当于知道(p,q),求解最小的正数解(a,b)使得(x)最小。
    • 显然这是经典的扩展欧几里得问题。

    因为这个题卡常,所以我们将枚举改成枚举质因子,注意一下最后质因子分解的时候也要先把素数筛出来,不然也会T。
    最后扩展欧几里得得到解的时候注意一下,我们可以选择正项或负项处理,我选择的是按负项处理直接得到答案。
    (这点纠结了一会儿,就是处理的时候和位置无关,按正项处理不论处理哪一个都是第一项,负项处理不论哪一个都是第二项。)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N = 35, MAX = 1e6 + 5;
    
    int T;
    ll n;
    
    bool chk[MAX];
    int prime[MAX], tot;
    
    void pre() {
        for(int i = 2; i < MAX; i++) {
            if(!chk[i]) {
                chk[i] = 1;
                prime[++tot] = i;
                for(ll j = 1ll * i * i; j < MAX; j += i) {
                    chk[j] = 1;
                }
            }
        }
    }
    
    void exgcd(ll a, ll b, ll &x, ll &y) {
        if(b == 0) {
            x = 1, y = 0;
            return ;
        }
        exgcd(b,a%b,x,y);
        ll z = x ;
        x = y;
        y = z - y * (a / b);
    }
    
    int cnt;
    ll tmp[N];
    
    ll calc(ll a, ll b) {
        ll x, y;
        exgcd(a, b, x, y);
        y = (y % a + a) % a;
        if(y * b >= 0) y -= a;
        return -y * b;//按负项处理
    }
    
    ll dfs(int num, ll a, ll b) {
        if(num > cnt) return calc(a, b);
        return min(dfs(num + 1, a * tmp[num], b), dfs(num + 1, a, b * tmp[num]));
    }
    
    int main() {
        ios::sync_with_stdio(false); cin.tie(0);
        pre();
        cin >> T;
        while(T--) {
            cin >> n;
            n <<= 1;
            cnt = 0;
            for(int i = 1; i <= tot; i++) {
                if(prime[i] > n) break;
                if(n % prime[i] == 0) {
                    tmp[++cnt] = 1;
                    ll now = prime[i];
                    while(n % prime[i] == 0) {
                        tmp[cnt] *= now;
                        n /= prime[i];
                    }
                }
            }
            if(n > 1) tmp[++cnt] = n;
            ll ans = dfs(1, 1, 1);
            cout << ans << '
    ';
        }
        return 0;
    }
    
  • 相关阅读:
    全文本的检索
    网卡配置
    linux解压命令
    Session
    swoole安装
    Linux 系统磁盘满处理方法
    php写入和读取文件内容
    PHP读取文件夹的文件列表
    php 公历农历互相转换
    PHP实现RESTful风格的API实例
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/11502960.html
Copyright © 2011-2022 走看看