18.12.1 Nuist_ACM集训队数论专场ABC题解

  • Problem A
  • Problem B
  • Problem C

Problem A

题目:
HDU-4704

Sample Input
2
Sample Output
2
Hint

  1. For N = 2, S(1) = S(2) = 1.
  2. The input file consists of multiple test cases. ==

这道题大致的意思就是给一个数N,问你将其分成1,2,3……N个数共有多少种分发。例如:4可以分成41,32,23,11,1,21,2,12,1,11,1,1,1;共8种分法。菜鸡没看懂题目,以为换了位置还算同一种。理解题意可知用排列组合的插空法计算并化简,即:S(0)+S(1)+S(2)+……+S(N)=CN0+CN1+……+CNNC_N^0+C_N^1+……+C_N^NCN0​+CN1​+……+CNN​=2N这个公式(实际是加到N-1,可是我打不出来上下两个N-1的标识,只能这样了)。那么现在的问题就是如何计算2的超大数次方取109+7的模。介于N的范围最大到10100000,long long肯定是存不下的,我的方法是用字符串一位一位取,下面给出大致解释:例如:2543=((25)10∗\ast∗ 24)10∗\ast∗ 23。所以对任意一个大数,用for循环就可以搞定,对于每次的10次方,快速幂即可。下面贴出代码:

#include  <iostream>
#include <cstdio>
#include <cstring>
#define mod 1000000007
using namespace std;
char a[1000005];//数字太大,当作字符串输进来
long long int len,biao[]={1,2,4,8,16,32,64,128,256,512},n,ans,i,t,flag=0;//只用2^0~2^9,直接打表了
int main()
{while(gets(a)){len=strlen(a);a[len-1]-=1;//减1flag=0; for(i=len-1;i>=0;i--)//退位问题{a[i]=a[i]-flag;flag=0;if(a[i]<'0'){a[i]=a[i]+10; flag=1;}else break;}ans=1;for(i=0;i<len;i++)//算法实现过程 {n=9;t=ans;while(n)//快速幂 {if(n&1)ans=ans*t%mod;//每次取模 t=t*t%mod;n>>=1;}t=biao[a[i]-'0'];ans=ans*t%mod;}cout<<ans<<endl;//结果 }return 0;
}

15ms通过,但看有0msAC的,上课还讲了其他的算法,但当时没听懂,到时候看看别人的题解再说

Problem B

题目:
HDU-1395
Give a number n, find the minimum x(x>0) that satisfies 2^x mod n = 1
Input
One positive integer on each line, the value of n.
Output
If the minimum x exists, print a line with 2^x mod n = 1.
Print 2^? mod n = 1 otherwise.
You should replace x and n with specific numbers.
Sample input
2
5
Sample Output
2^? mod 2 = 1
2^4 mod 5 = 1

思路: 这道题很明显能看出当n为偶数或1的时候是无解的,由欧拉定理可知奇数必有解 菜鸡看不懂就只能直接上链接不详细解释(其实了解就好了) 由于测试数据的设置,这题可以直接暴搜快速幂,但题目好坑,输出的句子中有几个空格,不认真看直接PE。下面直接贴代码:

#include <iostream>
#include <cstdio>
using namespace std;
int main()
{   int n,i,x,t,j;while(cin>>n){if(n%2==0||n==1)//偶数和1显然去除 printf("2^? mod %d = 1\n",n);//格式,有有有空格 else{for(i=2;;i++) //暴搜 {x=i-1;j=2;t=2;while(x)//快速幂 {if(x&1)t=t*j%n;j=j*j%n;x>>=1; }if(t==1)break;}printf("2^%d mod %d = 1\n",i,n);//空格空格空格}} return 0;
}

前面说到欧拉定理,其实这题可以它来对对暴搜的数据进行一次简化,来优化时间。由欧拉定理可知1~n-1中与n互质的数的个数m可使am≡\equiv≡ 1(mod n),但m不一定是最小值,所以对m中所有不与m互质的数进行搜索,找到即可。(原理解释:设p*q==m,且am≡\equiv≡ 1(mod n);则可能有ap≡\equiv≡ 1(mod n)且aq≡\equiv≡ 1(mod n),所以只要找出m中所有不与m互质的数(即那些pq)并对其进行搜索就好了,下面是优化后的代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define LL long long
using namespace std;
LL t,e[1000];
LL mod;
LL euler_phi(LL n)//欧拉函数,找到可能实现的最大值
{LL m=sqrt(n+0.5);LL ans=n,i;for(i=2;i<=m;i++)       if(n%i==0)        {      ans=ans/i*(i-1);while(n%i==0)n=n/i;}                 if(n>1)ans=ans/n*(n-1);return ans;
}
void find(LL n)//找到与m不互质的数,这些是可能的解
{    LL i;e[t++]=n;for(i=2;i*i<=n;i++)        if(n%i==0)                    if(i*i==n)                e[t++]=i;            else            {                e[t++]=i;                e[t++]=n/i;            }
}
LL pows(LL a,LL b)//快速幂后取模
{    LL s=1;    while(b)    {        if(b&1)            s=(s*a)%mod;a=(a*a)%mod;b>>=1;   }    return s;
}
int main()
{    LL n;      while(cin>>n){        if(n%2==0||n==1)printf("2^? mod %d = 1\n",n);else        {            LL m,ans,i,s=2;            m=euler_phi(n);t=0; find(m);sort(e,e+t);//要从小到大有序地找最小 mod=n;            for(i=0;i<t;i++)                           if(pows(2,e[i])==1)                {                    ans=e[i];                    break;                }                     printf("2^%d mod %d = 1\n",ans,n);       }    }    return 0;
}

优化之后,耗时直接从405ms降到了31ms,效果还是很显著的。
总感觉上课还讲了其他的解法

Problem C

题目:
HDU-5750
A positive proper divisor is a positive divisor of a number n, excluding n itself. For example, 1,2, and 3 are positive proper divisors of 6, but 6 itself is not.
Peter has two positive integers n and d. He would like to know the number of integers below n whose maximum positive proper divisor is d.
Input
There are multiple test cases. The first line of input contains an integer T (1≤T≤106)(1≤T≤106), indicating the number of test cases. For each test case:
The first line contains two integers n and d (2≤n,d≤109)(2≤n,d≤109).
Output
For each test case, output an integer denoting the answer.
Sample Inout
9
10 2
10 3
10 4
10 5
10 6
10 7
10 8
10 9
100 13
Sample Output
1
2
1
0
0
0
0
0
4

这题的大致意思是要找到比n小且最大因数为d的数的个数,转换思想理解,就是当d为素数时,找比d小且乘d小于n的素数的个数;当d不为素数时,求乘d小于n且小于等于d的最小素因数的素数的个数(关于为什么小于等于最小素因数,例:n=17430,d=385,d=5∗\ast∗ 7∗\ast∗ 11 ,当选到7时,找到的数为5∗\ast∗ 7∗\ast∗ 7∗\ast∗ 11=2695,而2695的最大因数为539=7∗\ast∗ 7∗\ast∗ 11,此时不满足,结束)。那么,现在所要做的问题是:1.找出素数2.判断中止。为防止TLE,找素数可以(最好)用欧拉筛法(没找到百度百科的链接)来筛选素数(同时,因筛时只要找d的素因数,打表打到34000就差不多了),将埃氏筛的O(nlogn)的时间复杂度降到O(n),具体实现在代码下说;中止判断条件由题意解析可知,以下为AC代码:

#include <iostream>
#define MAXN 34000
#define ll long long
using namespace std;
int num,prime[MAXN];
bool vis[MAXN];
void isprime()//欧拉筛法
{  ll i,j;num=0;for(i=2;i<=MAXN;++i) {if(!vis[i])prime[num++]=i;for(j=0;j<=num&&i*prime[j]<=MAXN;++j){vis[i*prime[j]]=true;if(i%prime[j]==0)break;//欧拉筛法缩时关键 } }
}
int main()
{int ans,i,N;ll n,d;isprime();//直接打表 std::ios::sync_with_stdio(false);//摆脱cin为保持与stdio同步而造成的TLE cin>>N;while(N--){cin>>n>>d;ans=0;for(i=0;i<num;++i){if(prime[i]>d||prime[i]*d>=n)//d为素数时的中止条件 break;if(d%prime[i]==0)//d为非素数时的中止条件 {++ans;break;}++ans;}cout<<ans<<endl;}return 0;
}

悲惨地被c++的cin同步问题卡成TLE,加std::ios::sync_with_stdio(false);关闭同步或者直接用scanf和printf就好
1887ms过的,看着那些三位数的羡慕
关于欧拉筛的缩时问题,很多人会对if(i%prime[j]==0)break; 这句话不理解,以下为解释:
欧拉筛法不是用i的倍数来消去合数,而是把prime里面纪录的素数,升序来当做要消去合数的最小素因子。当 iprime[j] 的倍数时,i=k∗\ast∗prime[j],如果继续运算 j+1,i∗\ast∗prime[j+1] = prime[j]∗\ast∗k∗\ast∗prime[j+1],这里prime[j] 是最小的素因子,当i = k∗\ast∗prime[j+1] 时会重复筛一遍,所以才跳出循环。

18.12.1 Nuist_ACM集训队数论专场ABC题解相关推荐

  1. ​十六周一次课(4月11日) 学习完成 18.11 LVS DR模式搭建 18.12 keepalived + LVS

    2019独角兽企业重金招聘Python工程师标准>>> 18.11 LVS DR模式搭建 准备工作:三台机器 分发器,也叫调度器(简写为dir) 192.134 rs1 192.13 ...

  2. 18.12.04 有品面试小记

    大冬天的面试真的是一件折磨人的事情,尤其是拖着一副重感冒的皮囊,分分钟病情加重,亲测有效. 可能是因为人多,面试是在一个小角落进行的,不过倒不是很在意,谁让自己对这个公司爱的深沉呢... 纪录下经过一 ...

  3. 程序员面试金典——18.12最大和子矩阵

    程序员面试金典--18.12最大和子矩阵 Solution1: 参考网址: [1]https://www.cnblogs.com/GodA/p/5237061.html 思想讲的很清楚~ [2]htt ...

  4. lombok导入报错,版本1.18.12已在maven本地仓库中

    项目场景: 跟着网上一位博主的教程搭建一个基于SSM的图书管理系统 SSM整合(图书管理系统) 问题描述: 在复制到Books.java类时,idea显示报错(我这里已修复,所以这里的导入语句没有报错 ...

  5. Navicat Premium 12.0.18 / 12.0.24安装与激活

    Navicat Premium 12.0.18 / 12.0.24安装与激活 若使用Navicat Premium 12.0.27请转至Navicat Premium 12.0.27安装与激活,其实每 ...

  6. “玲珑杯”ACM比赛 Round #18 ABC题解

    A -- 计算几何你瞎暴力 Time Limit:5s Memory Limit:256MByte Submissions:1597Solved:301 DESCRIPTION 今天HHHH考完了期末 ...

  7. 18.12.09-C语言练习:兔子繁衍问题 / Fibonacci 数列

    题目: 问题解析: 这是典型的/Fibonacci 数列问题.具体这里不赘述. 问题中不论是初始的第1对兔子还是以后出生的小兔子都是从第3个月龄起每个月各生一对兔子. 设n1,n2,n3分别是每个月1 ...

  8. c语言数位重排为最大数,18.12.09-C语言练习:黑洞数 / Kaprekar问题(示例代码)

    题目: 程序: 1 #include 2 3 int main(void) {4 intn, a, b, c, t, A, B;5 printf("输入一个三位数整数:");6 s ...

  9. arm64_linux head.S的执行流程(3.18)- 12.msm8996 地址空间布局

    1.前言 本文基于高通8996平台,kernel版本为3.18.31. 2. 8996内存地址空间布局 通过启动时的打印信息可以知道kernel image的虚拟地址空间布局如下: 结合bootloa ...

最新文章

  1. 系列文章--AJAX技术系列总结
  2. php smtp tls,php – RoundcubePostfix SMTP:SSL例程:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c...
  3. ack是什么,如何使用Ack机制,如何关闭Ack机制,基本实现,STORM的消息容错机制,Ack机制
  4. 中小企业利用VRRP实现链路负载均衡
  5. 用PHP制作饼图调查表
  6. 国内 RISC-V 产学研基地成立,Intel、Arm、RISC-V 将三分天下?
  7. OpenGL基础31:混合
  8. 转:在windows中将tree命令加入git-bash中
  9. 虚拟机 Bochs新版本试用DOS、UCDOS、Win3.2 -- Bochs 2.6.11于2020年1月5日发布!
  10. 项目管理工具与技术---项目风险管理中的工具与技术
  11. linux基础(十四)定时任务和管理系统的临时文件
  12. java中文繁体简体转换
  13. OpenHarmony学习笔记——编辑器访问Linux服务器进行编译
  14. 关于XDC工具的文章
  15. 微服务实践(总)-原文
  16. java将明文变为密文,使用java编程实现明文和密文之间的互转
  17. Python学习手册之数据类型
  18. MySql中的行锁和表锁的理解
  19. natapp搭建外网服务器
  20. 计算机二级考asc2码吗,2017年计算机二级考试ACCESS重要知识点

热门文章

  1. 无法访问局域网内打印机解决方法
  2. 堪称神器的 42 个 Chrome 插件,收藏!
  3. 学习python数据分析路线图_henry_dx_新浪博客
  4. Android视频滤镜添加硬解码方案
  5. 直播带货源码,Android中直播视频技术探究
  6. 彪哥情人节期间征女友一名铃声 彪哥情人节期间征女友一名手机...
  7. python【数据结构与算法】流水线作业调度Johnson启发式算法
  8. 周报(水管工问题,和图的遍历)
  9. 未来五年最值得投资的是哪个方向,为什么?
  10. 染书CRMA-从技术到运营,创建闭环式在线教育体系