2019牛客暑期多校训练营(第三场) - D - Big Integer - 数论
https://ac.nowcoder.com/acm/contest/883/D
\(A(n)\) 是由n个1组成的一个整数。
第一步:把 \(A(n)\) 表示为 \(\frac{10^n-1}{9}\) (第一步都想不出来)
那么 \(A(n)=0\;mod\;p\) ,当9和p互质的时候,存在一个 \(inv9\) ,那么原式即 \((10^n-1)*inv9=0\;mod\;p\)
两边乘9,移项得 \(10^n=1\;mod\;p\)
由欧拉定理,得 \(10^n=10^{n\;mod\;p-1}\;mod\;p\)
即这样的n必定是循环的,取 \(p-1\) 以内的一个研究
由费马小定理 \(a^{p-1} = 1\;mod\;p\) ,这样的n存在,且 \(n=p-1\)
这样,随着n增加,模p的余数必定是循环的,循环节的长度至多为 \(p-1\) ,那会不会有更短的呢?
考虑 \(d|p-1\) ,那么可以变形为 \(10^{p-1}=10^{d\frac{p-1}{d}}\;mod\;p\) 即 \((10^\frac{p-1}{d})^{d}=1\;mod\;p\)
这样最小的循环节必定是 \(p-1\) 的因数(赛中有发现),\(O(\sqrt {p})\) 枚举d,\(O(logd)\) 验证其是否是循环节(直接快速幂看看是不是和 \(10^0=1\;mod\;p\)一样就可以了)
目前复杂度\(O(\sqrt {p} logp)\)
找到最小的循环节之后,考虑怎么计数。那当然是要求 \(d|n\) 的个数,这样的(正整数)n明显在m以内有 \(\lfloor\frac{m}{d}\rfloor\)个。
但是套上 \(n=i^j\) 之后呢?猜测和d的质因数分解有关(赛中有发现)。
考虑i的质因数分解 \(i=p_1^{a_1}p_2^{a_2}p_3^{a_3}...p_k^{a_k}\)
则 \(i^j=p_1^{ja_1}p_2^{ja_2}p_3^{ja_3}...p_k^{ja_k}\)
分解d \(d=p_1^{b_1}p_2^{b_2}p_3^{b_3}...p_k^{b_k}\)
整除的条件,d是n的因子,则n的各个质因子覆盖d,即 \(ja_x>=b_x\) 对所有的 \(1<=x<=k\) 成立。
最值得学习的技巧来啦:考虑固定住j,那么合法的i满足什么条件才能满足上式呢?是d的每种质因子\(p_x\),i都至少要有\(\lceil\frac{b_x}{j}\rceil\)个
把这个值单独抽出来记为g \(g=p_x^{\lceil\frac{b_x}{j}\rceil}\),i要覆盖g,则\(g|i\),这样的i在n范围内有\(\lfloor\frac{n}{g}\rfloor\)个。
那么单个j的情况可以遍历d的质因子(分解的复杂度被上面对p的分解吸收,而分解后至多十几种质因子)求出。
当j变化时也会引起g的变化,具体来说每次j的变化可能会导致一些指数变小,但其实指数的总和至多就30多,也就是可以暴力对j进行统计。
在j超过最大的\(b_x\)之后,这样g变成1然后不再改变,以后的i都有n个。
那么特例为什么有2,3,5呢?首先3和9不互质,不存在这样的inv9,所幸3的倍数的各位数字之和都是3的倍数,考虑固定j=1,那么ans+=n/3,当j=2的时候,分别有1,4,9,16,25,36,一个不严谨的办法是继续ans+=n/3,而j=3的时候,分别是1,8,27,64,125,216,也是ans+=n/3。所以干脆就ans=(n*m)/3。
当2和5的时候, \(10^n = 1\;mod\;p\) 显然不可能成立,因为 \(10^n = 0\;mod\;p\) 显然成立。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int read() {
char c = getchar();
while(c < '0' || c > '9')
c = getchar();
int x = 0;
while(c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
}
return x;
}
int qpow(ll x, int n, int p) {
ll res = 1;
while(n) {
if(n & 1)
res = res * x % p;
x = x * x % p;
n >>= 1;
}
return res;
}
const int INF = 1e9 + 1;
int find_d(int p) {
int n = p - 1, d = INF;
for(int i = 1; i * i <= n; ++i) {
if(n % i == 0) {
if(qpow(10, i, p) == 1)
return i;
if(i * i != n) {
if(qpow(10, n / i, p) == 1) {
d = min(d, n / i);
}
}
}
}
return d;
}
int pk[50], bk[50], k;
int factor(int n) {
int maxbk = 0;
k = 0;
for(int i = 2; i * i <= n; ++i) {
if(n % i == 0) {
++k;
pk[k] = i;
bk[k] = 0;
while(n % i == 0) {
++bk[k];
n /= i;
}
maxbk = max(maxbk, bk[k]);
}
}
if(n != 1) {
++k;
pk[k] = n;
bk[k] = 1;
maxbk = max(maxbk, bk[k]);
}
return maxbk;
}
ll solve(int p, int n, int m) {
int d = find_d(p);
if(d == INF)
return 0;
int maxbk = factor(d);
ll ans = 0;
for(int j = 1; j <= m; ++j) {
int g = 1;
for(int i = 1; i <= k; ++i) {
g = g * qpow(pk[i], (bk[i] + j - 1) / j, p);
}
ans += n / g;
if(j >= maxbk) {
ans += 1ll * (m - j) * (n / g);
return ans;
}
}
return ans;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
int T = read();
while(T--) {
int p = read(), n = read(), m = read();
ll ans = 0;
switch(p) {
case 3:
ans = 1ll * (n / 3) * m;
break;
case 2:
break;
case 5:
break;
default:
ans = solve(p, n, m);
}
printf("%lld\n", ans);
}
}
既然有dalao喜欢开源模板……
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=40924149
include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
mt19937 mrand(random_device{}());
const ll mod=1000000007;
int rnd(int x) { return mrand() % x;}
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head
typedef pair<ll,ll> PLL;
namespace Factor {
const int N=1010000;
ll C,fac[10010],n,mut,a[1001000];
int T,cnt,i,l,prime[N],p[N],psize,_cnt;
ll _e[100],_pr[100];
vector<ll> d;
inline ll mul(ll a,ll b,ll p) {
if (p<=1000000000) return a*b%p;
else if (p<=1000000000000ll) return (((a*(b>>20)%p)<<20)+(a*(b&((1<<20)-1))))%p;
else {
ll d=(ll)floor(a*(long double)b/p+0.5);
ll ret=(a*b-d*p)%p;
if (ret<0) ret+=p;
return ret;
}
}
void prime_table(){
int i,j,tot,t1;
for (i=1;i<=psize;i++) p[i]=i;
for (i=2,tot=0;i<=psize;i++){
if (p[i]==i) prime[++tot]=i;
for (j=1;j<=tot && (t1=prime[j]*i)<=psize;j++){
p[t1]=prime[j];
if (i%prime[j]==0) break;
}
}
}
void init(int ps) {
psize=ps;
prime_table();
}
ll powl(ll a,ll n,ll p) {
ll ans=1;
for (;n;n>>=1) {
if (n&1) ans=mul(ans,a,p);
a=mul(a,a,p);
}
return ans;
}
bool witness(ll a,ll n) {
int t=0;
ll u=n-1;
for (;~u&1;u>>=1) t++;
ll x=powl(a,u,n),_x=0;
for (;t;t--) {
_x=mul(x,x,n);
if (_x==1 && x!=1 && x!=n-1) return 1;
x=_x;
}
return _x!=1;
}
bool miller(ll n) {
if (n<2) return 0;
if (n<=psize) return p[n]==n;
if (~n&1) return 0;
for (int j=0;j<=7;j++) if (witness(rand()%(n-1)+1,n)) return 0;
return 1;
}
ll gcd(ll a,ll b) {
ll ret=1;
while (a!=0) {
if ((~a&1) && (~b&1)) ret<<=1,a>>=1,b>>=1;
else if (~a&1) a>>=1; else if (~b&1) b>>=1;
else {
if (a<b) swap(a,b);
a-=b;
}
}
return ret*b;
}
ll rho(ll n) {
for (;;) {
ll X=rand()%n,Y,Z,T=1,*lY=a,*lX=lY;
int tmp=20;
C=rand()%10+3;
X=mul(X,X,n)+C;*(lY++)=X;lX++;
Y=mul(X,X,n)+C;*(lY++)=Y;
for(;X!=Y;) {
ll t=X-Y+n;
Z=mul(T,t,n);
if(Z==0) return gcd(T,n);
tmp--;
if (tmp==0) {
tmp=20;
Z=gcd(Z,n);
if (Z!=1 && Z!=n) return Z;
}
T=Z;
Y=*(lY++)=mul(Y,Y,n)+C;
Y=*(lY++)=mul(Y,Y,n)+C;
X=*(lX++);
}
}
}
void _factor(ll n) {
for (int i=0;i<cnt;i++) {
if (n%fac[i]==0) n/=fac[i],fac[cnt++]=fac[i];}
if (n<=psize) {
for (;n!=1;n/=p[n]) fac[cnt++]=p[n];
return;
}
if (miller(n)) fac[cnt++]=n;
else {
ll x=rho(n);
_factor(x);_factor(n/x);
}
}
void dfs(ll x,int dep) {
if (dep==_cnt) d.pb(x);
else {
dfs(x,dep+1);
for (int i=1;i<=_e[dep];i++) dfs(x*=_pr[dep],dep+1);
}
}
void norm() {
sort(fac,fac+cnt);
_cnt=0;
rep(i,0,cnt) if (i==0||fac[i]!=fac[i-1]) _pr[_cnt]=fac[i],_e[_cnt++]=1;
else _e[_cnt-1]++;
}
vector<ll> getd() {
d.clear();
dfs(1,0);
return d;
}
vector<ll> factor(ll n) {
cnt=0;
_factor(n);
norm();
return getd();
}
vector<PLL> factorG(ll n) {
cnt=0;
_factor(n);
norm();
vector<PLL> d;
rep(i,0,_cnt) d.pb(mp(_pr[i],_e[i]));
return d;
}
bool is_primitive(ll a,ll p) {
assert(miller(p));
vector<PLL> D=factorG(p-1);
rep(i,0,SZ(D)) if (powl(a,(p-1)/D[i].fi,p)==1) return 0;
return 1;
}
int findorder(ll a,ll p) {
assert(miller(p));
vector<PLL> D=factorG(p-1);
int t=p-1;
rep(i,0,SZ(D)) {
while (t%D[i].fi==0&&powl(a,t/D[i].fi,p)==1) t/=D[i].fi;
}
return t;
}
}
int _,p;
ll n,m;
int main() {
Factor::init(100000);
for (scanf("%d",&_);_;_--) {
scanf("%d%lld%lld",&p,&n,&m);
if (p==2||p==5) {
puts("0");
continue;
}
if (p==3) {
printf("%lld\n",m*(n/3));
continue;
}
ll x=Factor::findorder(10,p);
vector<PLL> dd=Factor::factorG(x);
ll ans=0;
for (int i=1;i<=m;i++) {
ll y=1;
int me=0;
for (auto q:dd) {
int e=(q.se+i-1)/i;
me=max(me,e);
rep(j,0,e) y=y*q.fi;
}
if (me==1) {
ans+=(n/y)*(m-i+1);
break;
} else {
ans+=n/y;
}
}
printf("%lld\n",ans);
}
}
2019牛客暑期多校训练营(第三场) - D - Big Integer - 数论的更多相关文章
- 2019牛客暑期多校训练营(第三场)H题目
题意:给你一个N×N的矩阵,求最大的子矩阵 满足子矩阵中最大值和最小值之差小于等于m. 思路:这题是求满足条件的最大子矩阵,毫无疑问要遍历所有矩阵,并判断矩阵是某满足这个条件,那么我们大致只要解决两个 ...
- 2019牛客暑期多校训练营(第三场)- F Planting Trees
题目链接:https://ac.nowcoder.com/acm/contest/883/F 题意:给定n×n的矩阵,求最大子矩阵使得子矩阵中最大值和最小值的差值<=M. 思路:先看数据大小,注 ...
- 2019牛客暑期多校训练营(第三场) F.Planting Trees(单调队列)
题意:给你一个n*n的高度矩阵 要你找到里面最大的矩阵且最大的高度差不能超过m 思路:我们首先枚举上下右边界,然后我们可以用单调队列维护一个最左的边界 然后计算最大值 时间复杂度为O(n*n*n) # ...
- 2019牛客暑期多校训练营(第九场)A:Power of Fibonacci(斐波拉契幂次和)
题意:求Σfi^m%p. zoj上p是1e9+7,牛客是1e9: 对于这两个,分别有不同的做法. 前者利用公式,公式里面有sqrt(5),我们只需要二次剩余求即可. 后者mod=1e9,5才 ...
- 2019牛客暑期多校训练营(第一场)A题【单调栈】(补题)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 题目描述 Two arrays u and v each with m distinct elem ...
- 2019牛客暑期多校训练营(第一场) B Integration (数学)
链接:https://ac.nowcoder.com/acm/contest/881/B 来源:牛客网 Integration 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 5242 ...
- 2019牛客暑期多校训练营(第一场) A Equivalent Prefixes ( st 表 + 二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A 来源:牛客网 Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/ ...
- 2019牛客暑期多校训练营(第二场)F.Partition problem
链接:https://ac.nowcoder.com/acm/contest/882/F来源:牛客网 Given 2N people, you need to assign each of them ...
- 2019牛客暑期多校训练营(第一场)A Equivalent Prefixes(单调栈/二分+分治)
链接:https://ac.nowcoder.com/acm/contest/881/A来源:牛客网 Two arrays u and v each with m distinct elements ...
- [状态压缩,折半搜索] 2019牛客暑期多校训练营(第九场)Knapsack Cryptosystem
链接:https://ac.nowcoder.com/acm/contest/889/D来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144K,其他语言52428 ...
随机推荐
- LTE抛弃了CDMA?
原文链接:https://blog.csdn.net/readhere/article/details/82764919 本文节选自<LTE教程:结构与实施> 大家都听说过这样的说法:LT ...
- C#笔试总结
题一: 程序设计: 猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒.(C#语言)要求: <1>.构造出Cat.Mouse.Master三个类,并能使程序运行 ...
- 服务器中常见的RAID
Standalone 最普遍的单磁盘储存方式. Cluster 集群储存是通过将数据分布到集群中各节点的存储方式,提供单一的使用接口与界面,使用户可以方便地对所有数据进行统一使用与管理. Hot sw ...
- mui初级入门教程(四)— 再谈webview,从小白变“大神”!
文章来源:小青年原创发布时间:2016-06-05关键词:mui,html5+,webview转载需标注本文原始地址: http://zhaomenghuan.github.io/#!/blog/20 ...
- 5个用/不用GraphQL的理由
我在如何使用Gatsby建立博客 / How to build a blog with Gatsby这篇文章中提过GraphQL在Gatsby中的应用.总的来讲,它是一个新潮的技术,在适宜的使用场景威 ...
- 无障碍(Accessible Rich Internet Applications)
可访问性就是让你的网站能够尽可能为越来越多的人可用的做法,这意味着需要竭尽全力不要将任何访问信息的人挡在门外,仅仅因为他们可能有某些方面的残疾或者因为某些个人情况例如他们正在使用的设备.他们的网速.或 ...
- git全套详细教程
git安装 首先,我们要去git的官网下载一个git安装包,双击到无关紧要的步骤我就不详细描述了,直接介绍我们关键的步骤. 选择git包含的内容和打开方式 选择都很清晰,具体情况我不是很清楚,不过选择 ...
- 013-Spring Boot web【二】静态资源、Servlet、Filter、listenter
一.静态资源 1.1.webapp默认支持静态资源 在src/main/webapp下建立user.html默认支持访问 1.2.默认内置静态资源目录.可被直接访问 查看包:spring-boot-a ...
- Map 接口有哪些类
Map接口 Map提供了一种映射关系,其中的元素是以键值对(key-value)的形式存储的,能够实现根据key快速查找value:Map中的键值对以Entry类型的对象实例形式存在:建(key值)不 ...
- 阶段1 语言基础+高级_1-3-Java语言高级_1-常用API_1_第4节 ArrayList集合_13-ArrayList集合概述和基本使用
新建类 多了个尖括号,大写字母E,这是什么意思呢? 尖括号当中叫做泛型.存储的统一的类型,这个类型就在尖括号里面写上,我们用一个字母占位表示. 如何创建呢 构造方法有三个,最常用的就是无参构造 先掌握 ...