2019 Multi-University Training Contest 3 - 1006 - Fansblog - 打表 - 暴力

Posted yinku

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2019 Multi-University Training Contest 3 - 1006 - Fansblog - 打表 - 暴力相关的知识,希望对你有一定的参考价值。

http://acm.hdu.edu.cn/showproblem.php?pid=6608

题意:给一个比较大的质数P(1e14以内),求比它小的最大的质数Q(貌似保证存在的样子,反正我没判不存在),求Q!modP的值。

一开始觉得是个什么神仙题,但是怎么全场都绿了一片,瞬时感觉智商受到了侮辱。想了很多什么奇奇怪怪的性质,都不太清楚,然后队友卡1007的时候我打了个对P找ans的表看了一下。发现当P-Q=2的时候就是ans=1???

然后打个(P-2)!%P的表,发现小数据都这样过,估计也是真的这样子。

那么考虑怎么找这个Q,首先肯定特判掉P=3,然后Q必然是奇数。

考虑暴力找Q的复杂度:首先根据质数定理(或者直接打1e7表出来知道)得到质数的数量大概6e5这样子,验证Q是质数一圈暴力。

假如Q不是质数,极端情况,是两个不同质数的积,那么这样的数的分布应该是很大的。

根据下面的代码可以打出这样的极端合数:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e7;

int pri[MAXN + 5], pritop;
bool notpri[MAXN + 5];
//pritop从1开始计数

void sieve(int n) 
    notpri[1] = 1;
    for(int i = 2; i <= n; i++) 
        if(!notpri[i])
            pri[++pritop] = i;
        for(int j = 1; j <= pritop && i * pri[j] <= n; j++) 
            notpri[i * pri[j]] = 1;
            if(i % pri[j] == 0)
                break;
        
    
    printf("ptop=%d\n", pritop);


vector<ll> H;

int main() 
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    sieve(MAXN);
    for(int i = pritop; i >= pritop - 100; --i) 
        for(int j = i - 1; j >= i - 1 - 100; --j) 
            H.push_back(1ll*pri[i]*pri[j]);
        
    
    sort(H.begin(),H.end(),greater<ll>());
    for(int i=0;i<100;++i)
        printf("i=%d num=%lld\n",i+1,H[i]);
    
    return 0;

可以看到这样的极端合数之间的间隔非常大!两个之间差了1e6以上!

ptop=664579
i=1 num=99999640000243
i=2 num=99999620000261
i=3 num=99999440000783
i=4 num=99999340000513
i=5 num=99999280000567
i=6 num=99999220000621
i=7 num=99999200000639
i=8 num=99999160001539
i=9 num=99999140001653
i=10 num=99999100001701
i=11 num=99999080001827
i=12 num=99999040001863
i=13 num=99999020002001
i=14 num=99999020001917
i=15 num=99999000002059
i=16 num=99998980000837
i=17 num=99998920000891
i=18 num=99998800003591
i=19 num=99998800002511
i=20 num=99998800000999

假如把三个不同质数的乘积也放上来,基本也是没有缩小到哪里。

所以可以猜测,在一次暴力验证的过程中,在找到Q之前,遇到的极端合数的数量估计不会超过10个,甚至不会超过5个。其他的合数的素因子很容易被判断掉了,几乎只是暴力判Q的零头,忽略不计。

质数之间的间隔的话,根据质数的总数量,平均是32个出现一个,当然在比较大的时候间隔较远,但是我猜测不会超过1000,连续1000个数都没有质数的,希望大佬给出一个估计?

那么大概暴力判一次Q,最差情况在6e6左右,考虑T比较小(后面题面改来改去差评),直接暴力。

根据猜测的结果(威尔逊定理):(P-2)! = 1 mod P ,每次两边乘两个个逆元也可以转移到下一个数,至多转移1000次,1000log1e14也是零头,忽略不计。

最后要小心溢出,改了很多地方,乘逆元的地方都改了__int128但是快速幂里面没改,导致溢出WA1,太坑了。

其实只是使用乘法取模,可以用快速乘的。

以上是关于2019 Multi-University Training Contest 3 - 1006 - Fansblog - 打表 - 暴力的主要内容,如果未能解决你的问题,请参考以下文章

2019 Multi-University Training Contest 6

2019 Multi-University Training Contest 6

2019 Multi-University Training Contest 6

2019 Multi-University Training Contest 3

2019 Multi-University Training Contest 2

2019 Multi-University Training Contest 2