数论专场 Day9 部分题解
// 2019年西电暑期集训
// [7月9日]基础数论:https://cn.vjudge.net/contest/309097
A - Visible Lattice Points
题目大意:
平面上有N*N个格点,问从原点(0,0)能够看到多少个不被遮挡的点。
数据范围:1<=N<=1000,测试组数:1<=C<=1000。
分析及代码:
暴力计算复杂度N*N*C,肯定T。看题目所给几组样例,也没有发现有什么规律。
注意到点的分布的对称性,对于每一列(x=xi),记录在直线y=x以下能看到的点的坐标:
(1,1)
(2,1)
(3,1),(3,2)
(4,1),(4,3)
(5,1),(5,2),(5,3),(5,4)
......
可以发现直线x=xi上的点的个数为与xi互质的个数,即欧拉函数值phi(xi)。
由对称性,(1,1)重复计算,加上点(1,0)与(0,1),所以本题答案为2*∑phi(xi) + 1。
#include <iostream>
#include <cstdio>
using namespace std; const int maxn = ;
int phi[maxn+]; void phi_table(int n) { // O(nlogn) n以内欧拉表
int i, j;
for(i=;i<=n;i++)
phi[i] = i; for(i=;i<=n;i+=)
phi[i] /= ; for(i=;i<=n;i+=) {
if(phi[i]==i) {
for(j=i;j<=n;j+=i)
phi[j] = phi[j] / i * (i - );
}
} for(int i=;i<=n;i++) { // 前缀和
phi[i] += phi[i-];
}
} int main()
{
phi_table();
int T, t = , n;
cin>>T;
while(t++<T) {
scanf("%d", &n);
printf("%d %d %d\n", t, n, phi[n]*+);
}
return ;
}
B - Super A^B mod C
题目大意:
计算A^B (mod C)的结果,其中1<=A,C<=1000000000,1<=B<=10^1000000。
分析及代码:
B的数位长度达到了1000000位,即使利用快速幂logn的算法也有些勉强。。。
依稀记得有一个欧拉定理(费马小定理),计算当m为素数时a^b % m结果为a^(b%(m-1)),指数立刻收缩到了ll范围内。
这里需要用到a和m不互质情况下的欧拉降幂公式:

至于为什么我AC的代码指数没有加上phi(C)也过了,我也不懂O.O
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = ;
typedef long long ll;
ll a, c;
char b[maxn]; ll phi(ll x) { // 欧拉函数
ll res = x;
for(int i=;i<=x/i;i++) {
if(x%i==) {
res = res/i*(i-);
while(x%i==) x/=i;
}
}
if(x>) res = res/x*(x-);
return res;
} ll pow(ll a, ll n) { // 快速幂
ll res = ;
while(n) {
if(n&) res = res * a % c;
a = a*a % c;
n >>= ;
}
return res;
} int main() {
while(scanf("%lld", &a)!=EOF) {
scanf("%s", b);
scanf("%d", &c);
ll exp = , p = phi(c);
for(int i=;b[i];i++) {
exp *= ;
exp += b[i]-'';
exp %= p;
}
// exp += p;
printf("%lld\n", pow(a, exp));
}
return ;
}
D - The Euler function
题目大意:
求一段区间的欧拉函数值的和。(2<a<b<3000000)
分析及代码:
欧拉函数裸题,使用O(nlogn)欧拉筛预处理。
(预先求前缀和的算法比直接区间求和要慢。。。)
#include <iostream>
#include <cstdio>
using namespace std; const int maxn = ;
typedef long long ll;
ll phi[maxn]; void phi_table(int n)
{
int i, j;
for(i=;i<=n;i++)
phi[i] = i; for(i=;i<=n;i+=)
phi[i] /= ; for(i=;i<=n;i+=) {
if(phi[i]==i) {
for(j=i;j<=n;j+=i)
phi[j] = phi[j] / i * (i - );
}
} for(int i=;i<=n;i++) {
phi[i] += phi[i-];
}
} int main()
{
phi_table();
int a, b;
while(scanf("%d %d", &a, &b)!=EOF) { // 此题直接写for循环更快
printf("%lld\n", phi[b]-phi[a-]);
}
return ;
}
E - Strange Way to Express Integers
题目大意:
中国剩余定理裸题。。。
分析及代码:
还不是特别熟悉,网上找了份mi不互质的模板,稍微改改就直接A了。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = ;
ll exgcd(ll a, ll b, ll& x, ll& y) {
ll d = a;
if(b!=) {
d = exgcd(b, a%b, y, x);
y -= (a/b) * x;
} else {
x = ; y = ;
}
return d;
} ll a[maxn], m[maxn], n;
ll CRT() {
if (n == ) {
if (m[] > a[]) return a[];
else return -;
}
ll x, y, d;
for (int i = ; i < n; i++) {
if (m[i] <= a[i]) return -;
d = exgcd(m[], m[i], x, y);
if ((a[i] - a[]) % d != ) return -; //不能整除则无解
ll t = m[i] / d;
x = ((a[i] - a[]) / d * x % t + t) % t; //第0个与第i个模线性方程的特解
a[] = x * m[] + a[];
m[] = m[] * m[i] / d;
a[] = (a[] % m[] + m[]) % m[];
}
return a[];
} int main() {
while(scanf("%lld", &n)!=EOF) {
for(int i=;i<n;i++) {
scanf("%lld %lld", &m[i], &a[i]);
}
printf("%lld\n", CRT());
}
return ;
}
F - C Looooops
题目大意:
求A + Cx = B (mod 2^k) 的x最小正整数解。
分析及代码:
上式变形得到
C*x + 2^k*y = B-A
利用扩展欧几里得ax+by=gcd(a,b)解该同余方程,得到x。
- 若 (B-A) % gcd(a, b) 不为0,则无解。
- 否则 x = x * (B-A) / gcd(a, b) ,得到 原方程的特解。
- 原方程的全部解为 x + m * C / gcd(a, b), m∈Z
- 令 s = C / gcd(a, b)
- 所以最小的整数解为 (x%s + s) % s
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
// d = gcd(a, b) = ax + by
ll exgcd(ll a, ll b, ll& x, ll& y) {
ll d = a;
if(b!=) {
d = exgcd(b, a%b, y, x);
y -= (a/b) * x;
} else {
x = ; y = ;
}
return d;
}
// Ax = B (mod C)
ll solve(ll A, ll B, ll C){
ll x, y;
ll d = exgcd(A, C, x, y);
if(B%d!=){
return -; // 无解
}
x *= B/d;
ll s = C/d;
return (x%s + s)%s;
}
int main()
{
int A, B, C, k;
while(scanf("%d %d %d %d", &A, &B, &C, &k)!=EOF && A+B+C+k) {
ll ans = solve(C, B-A, (ll)<<k); // A+Cx = B (mod 2^k)
if(ans==-) {
printf("FOREVER\n");
} else {
printf("%lld\n", ans);
}
}
return ;
}
G - Divisors
题目大意:
求组合数C(n, k)的因子个数。(0 ≤ k ≤ n ≤ 431)
分析及代码:
一看n,k都不大,直接将定义式的连乘项分解,统计每个素因子的出现次数。
然后有那啥公式,每个素因子个数+1后再相乘即为答案,交一发T了。
加上素数筛,还是T了。优化 了下,T了。改对n,k的记忆化,还是T了。
。。。
来学习一下求n!某个因子个数的方法:(去年博客)
// 公式:cnt = [n/p] + [n/p^2] + [n/p^3] +...+ [n/p^k]
// 核心代码:
int cnt = ;
while(n) {
cnt += n/p;
n /= p;
}
终于AC的代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = ;
int cnt[maxn], n, k;
int p[maxn], num;
void init() {
for(int i=;i<maxn;i++) {
bool isp = true;
for(int j=;j*j<=i;j++) {
if(i%j==) {
isp = false;
break;
}
}
if(isp) p[num++] = i;
}
} int cal(int n, int p) {
int res = ;
while(n) {
res += n/p;
n /= p;
}
return res;
}
int main()
{
init();
while(scanf("%d %d", &n, &k)!=EOF) {
long long ans = ;
for(int i=;i<num && p[i]<=n;i++) { // 没有p[i]<=n TLE!!!
long long cnt = ;
cnt += cal(n, p[i]);
cnt -= cal(k, p[i]);
cnt -= cal(n-k, p[i]);
ans *= (cnt+);
}
printf("%lld\n", ans);
}
return ;
}
H - 青蛙的约会
题目大意:
同F题,求同余方程 x-y + (m-n) * k = 0 (mod L) k的最小正整数解。
分析及代码:
按照F的推导过程慢慢推吧。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
// d = gcd(a, b) = ax + by
ll exgcd(ll a, ll b, ll& x, ll& y) {
ll d = a;
if(b!=) {
d = exgcd(b, a%b, y, x);
y -= (a/b) * x;
} else {
x = ; y = ;
}
return d;
}
// Ax = B (mod C)
ll solve(ll A, ll B, ll C){
ll x, y;
ll d = exgcd(A, C, x, y);
if(B%d!=){
return -; // 无解
}
x *= B/d;
ll s = C/d;
return (x%s + s)%s;
} int main()
{
ll x, y, m, n, L;
cin>>x>>y>>m>>n>>L;
ll ans;
if(m>n) ans = solve(m-n, y-x, L); // m-n>0
else ans = solve(n-m, x-y, L);
if(ans==-) {
printf("Impossible\n");
} else {
printf("%lld\n", ans);
}
return ;
}
I - Semi-prime H-numbers
题目大意:
定义类似4*k+1的正整数为H数。H数分为两种,H素数和H合数,合数中只能分解成两个H素数相乘形式的为H半素数。
求一个区间内H半素数的个数。
分析及代码:
模仿素数筛的写法,很容易实现O(nlogn)的H素数筛法。
在筛选过程中,将H数为标记为三种类别,素数、半素数、合数。
最后将所有含有半素数标记的取出,采用upper_bound二分查找可以快速得到答案。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = ;
int Htype[maxn]; // 0:prime 2:semi-prime 1:composite
//int p[maxn], num;
int pp[maxn], num2;
void init() {
// Htype[1] = isp[5] = 0;
for(int i=;i<maxn;i+=) {
if(!Htype[i]) {
//p[num++] = i;
if(i<maxn/i) Htype[i*i] = ; for(int j=*i;j<maxn;j+=i) {
if(j%==) {
Htype[j] = ;
if((j/i)%== && !Htype[j/i])
Htype[j] = ;
}
}
}
} for(int i=;i<maxn;i+=) {
if(Htype[i]==) {
pp[num2++] = i;
} }
} int main()
{
init();
int h;
while(scanf("%d", &h)!=EOF && h) {
printf("%d ", h);
printf("%d\n", upper_bound(pp, pp+num2, h) - pp);
}
return ;
}
(未完待续)
数论专场 Day9 部分题解的更多相关文章
- DAY 3 数论专场
2019-07-23 今天的题目一个比一个神仙,很早之前就在讨论今天是不是晚上回宾馆就没脑子了,后来发现,是中午.... 一上午就讲了一个PPT,然而标题就两个子---数论... 这谁顶的住....整 ...
- SPOJ - POLYNOM Polynomial(数论乱搞)题解
题意 :给你n个数,问你是否存在一个多项式(最多三次方)满足f(i)= xi. 思路:讲一个神奇的思路: x3 - (x - 1)3 = 3x2 - 3x + 1 x2 - (x - 1)2 = 2x ...
- 【CYH-02】noip2018数论模拟赛:赛后题解
1.小奔的矩阵 2.大奔的方案 3.小奔与不等四边形 4.小奔的方案 当然本次比赛肯定难度不会仅限于此啦!后续还会--
- 【数论】8.30题解-prime素数密度 洛谷p1835
prime 洛谷p1835 题目描述 给定区间[L, R](L <= R <= 2147483647, R-L <= 1000000),请计算区间中 素数的个数. 输入输出 输入 两 ...
- NOI2010能量采集(数论)
没想到NOI竟然还有这种数学题,看来要好好学数论了…… 网上的题解: 完整的结题报告: 首先我们需要知道一个知识,对于坐标系第一象限任意的整点(即横纵坐标均为整数的点)p(n,m),其与原点o(0,0 ...
- 【LOJ#3096】[SNOI2019]数论
[LOJ#3096][SNOI2019]数论 题面 LOJ 题解 考虑枚举一个\(A\),然后考虑有多少个合法的\(B\). 首先这个数可以写成\(a_i+kP\)的形式,那么它模\(Q\)的值成环. ...
- NOIp2017——追求那些我一直追求的
谨以此祭奠我即将爆炸的NOIP2017. $Mingqi\_H\ \ 2017.09.24$ Day -47 突然发现半年来自己从来没有写对过SPFA,最近几天才发现自己的板子一直是错的...赶紧找个 ...
- CSU训练分类
√√第一部分 基础算法(#10023 除外) 第 1 章 贪心算法 √√#10000 「一本通 1.1 例 1」活动安排 √√#10001 「一本通 1.1 例 2」种树 √√#10002 「一本通 ...
- 【CodeForces】585 E. Present for Vitalik the Philatelist
[题目]E. Present for Vitalik the Philatelist [题意]给定n个数字,定义一种合法方案为选择一个数字Aa,选择另外一些数字Abi,令g=gcd(Ab1...Abx ...
随机推荐
- POJ 2763 /// 基于边权的树链剖分
题目大意: 给定n个结点,有n-1条无向边,给定每条边的边权 两种操作,第一种:求任意两点之间路径的权值和,第二种:修改树上一点的权值. 因为是一棵树,可以直接把 u点和v点间(假设u为父节点,v为子 ...
- 转Git仓库分支(Branch)和标签(Tag)
仓库的分支(Branch)规范,影响到每个团队的工作流的一致性:标签(Tag)便于开发团队.测 试团队和其他团队识别每个项目的版本,特别是在协同处理线上问题的时候,大家可以非常清楚 地知道线上运行版本 ...
- hashmap1.7的死锁模拟
package com.cxy.springdataredis.hashmap; import javax.lang.model.element.VariableElement; import jav ...
- iOS开发系列-Lock
概述 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生. iOS中锁之前的性能的图标排行: ...
- Java Queue队列
前言 Queue队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作,LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用. ...
- 获取硬件信息的delphi源码CPUID、操作系统、Mac物理地址、计算机名称、IP地址、用户名
{-----------------------------------------------------------------------------作者:sushengmiyan 2013.0 ...
- 运维人员最常用150个linux命令汇总
命令 功能说明 线上查询及帮助命令(2个) man 查看命令帮助,命令的词典,更复杂的还有info,但不常用. help 查看Linux内置命令的帮助,比如cd命令. 文件和目录操作命令(18个) l ...
- PostgreSQL 优势,MySQL 数据库自身的特性并不十分丰富,触发器和存储过程的支持较弱,Greenplum、AWS 的 Redshift 等都是基于 PostgreSQL 开发的
PostgreSQL 优势 2016-10-20 21:36 686人阅读 评论(0) 收藏 举报 分类: MYSQL数据库(5) PostgreSQL 是一个自由的对象-关系数据库服务器(数据库 ...
- Java学习之Java历史版本
Java有三个版本,标准版Java SE,企业版Java EE,移动版Java ME.按理来说,每一种版本都会有自己的版本号,但是约定俗成:JDK版本号=Java SE版本号=Java版本号,这是因为 ...
- 牛客网NOIP赛前集训营-普及组(第七场)
链接:C 来源:牛客网 牛牛的同学给牛牛表演了一个读心术:牛牛先任意选定一个非负整数,然后进行N次操作:每次操作前,假设牛牛当前的数是a,那么这个操作可能是a = a + x, 或者a = a * x ...