[HDU3292] 求第K大数


题目描述

  战国时期齐国君主非常喜欢管类乐器,尤其喜欢竽,他有自己的一支奏竽的乐队,其中乐队的人数是一个正方形数(每行每列都有X个人)。每天下午他都会让自己的乐队排成正方形为自己演奏。
  国王不知道,其中有一个叫南郭的人,其实根本不会吹竽,也混在其中。国王去世后他的儿子继承父位,新国王不喜欢父亲的欣赏方式,他打算把父亲的竽乐队分成若干几个正方形数,然后分别为他演奏,南郭先生听说后非常害怕,于是偷偷逃走了。结果国王重排乐队之后,发现剩下的人正好分组Y^2人的N组。


输入格式

输入有多组数据,每组占一行包含两个正整数N(2<=N<29),K(K<10^9)


输出格式

输出第K大的解满足条件的X mod 8191的值,如果没有这样的X存在,则输出“No Answers”。


样例数据

样例输入

2 999888
3 1000001
4 8373

样例输出

7181
600
No Answers


题目分析

x^2-n*y^2=1:佩尔方程
n为完全平方数时方程无解
暴力求出最小整数解(当然也可以用麻烦的连分数解法)然后矩阵快速幂

[xkyk]=[x1y1dy1x1]k1[x1y1]


源代码

#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef long long LL;
inline const int Get_Int() {
    int num=0,bj=1;
    char x=getchar();
    while(x<'0'||x>'9') {
        if(x=='-')bj=-1;
        x=getchar();
    }
    while(x>='0'&&x<='9') {
        num=num*10+x-'0';
        x=getchar();
    }
    return num*bj;
}
const int maxn=5,mod=8191;
struct Matrix {
    LL n,m,a[maxn][maxn];
    Matrix(LL n,LL m) {
        this->n=n;
        this->m=m;
        memset(a,0,sizeof(a));
    }
    Matrix(LL n,LL m,char E) { //单位矩阵
        this->n=n;
        this->m=m;
        memset(a,0,sizeof(a));
        for(int i=1; i<=n; i++)a[i][i]=1;
    }
    void init(LL n,LL m) {
        this->n=n;
        this->m=m;
        memset(a,0,sizeof(a));
    }
    LL* operator [] (const LL x) {
        return a[x];
    }
    Matrix operator = (Matrix b) {
        init(b.n,b.m);
        for(int i=1; i<=b.n; i++)
            for(int j=1; j<=b.m; j++)
                a[i][j]=b[i][j];
    }
    Matrix operator + (Matrix& b) {
        for(int i=1; i<=b.n; i++)
            for(int j=1; j<=b.m; j++)
                a[i][j]+=b[i][j];
    }
    void operator += (Matrix& b) {
        *this=*this+b;
    }
    Matrix operator - (Matrix& b) {
        for(int i=1; i<=b.n; i++)
            for(int j=1; j<=b.m; j++)
                a[i][j]-=b[i][j];
    }
    void operator -= (Matrix& b) {
        *this=*this-b;
    }
    Matrix operator * (LL k) {
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
                a[i][j]*=k;
    }
    void operator *= (LL k) {
        *this=*this*k;
    }
    Matrix operator * (Matrix& b) {
        Matrix c(n,b.m);
        for(int i=1; i<=n; i++)
            for(int j=1; j<=b.m; j++)
                for(int k=1; k<=m; k++)
                    c[i][j]=(c[i][j]+a[i][k]*b[k][j])%mod;
        return c;
    }
    void operator *= (Matrix& b) {
        *this=*this*b;
    }
    Matrix operator ^ (LL b) {
        Matrix ans(n,m,'e'),a=*this;
        while(b>0) {
            if(b&1)ans=ans*a;
            a*=a;
            b>>=1;
        }
        return ans;
    }
    void Output() {
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=m; j++)
                printf("%lld ",a[i][j]);
            putchar('\n');
        }
    }
};
LL x,y;
void Get_Answer(LL d) { //找到佩尔方程最小特解 
    y=1;
    while(true) {
        x=sqrt(d*y*y+1);
        if(x*x-d*y*y==1)break;
        y++;
    }
} 
//x^2-n*y^2=1
LL n,k;
int main() {
    while(scanf("%lld%lld",&n,&k)!=EOF) {
        int t=sqrt(n);
        if(t*t==n) {
            puts("No Answers");
            continue;
        }
        Get_Answer(n);
        Matrix a(2,2);
        a.a[1][1]=x%mod;
        a.a[1][2]=y*n%mod;
        a.a[2][1]=y%mod;
        a.a[2][2]=x%mod;
        a=a^(k-1);
        x=(a.a[1][1]*x%mod+a.a[1][2]*y%mod)%mod;
        printf("%lld\n",x);
    }
    return 0;
}

好的,关于 HDU4992 所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根。原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了模 n 意义下的所有原根,我们需要先出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于最大公约数,phi 函数用于欧拉函数,pow 函数用于快速幂模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值