NOIP 2017.10.20 总结+心得
来源:互联网 发布:网络剧老炮儿2 编辑:程序博客网 时间:2024/05/18 13:25
(以此纪念S7死在8强的卫冕冠军)
世界中的很大
今天考试,数论的第二试
怎么说呢,今天的预计最好得分应该是240,然而实际得分130
这当然是自己的问题,然而还剩下许多可以总结的地方,尤其是第一题,做不出来简直是自己害死的自己
第三题也算是一个警醒了,多说无益
看题先:
1。
当时考试的时候,一看这个函数,恩,欧拉函数求和直接就是n了,然后感觉可以抛开前面一坨,反正m只有10,最后快速幂乘上就好
那么问题就变成了预处理右面一坨
1e7的数据啊~~
只有O(n)了,线筛吧?
那就需要这玩意儿是一个积性函数了
约数个数,莫比乌斯,单位函数,全是积性函数。。。
那这个肯定是积性函数了
打个表验证一下。。
咦怎么不是积性函数!?幸好验证了,排除线筛,想其他做法,未果,打了个1e5的表,无法编译。。。
最后五分钟。。表打错了!表打错了!表打错了!
就是积性函数!!!!!!!!
时间不够了。。
下午改,稍微分析一波线筛一遍出来。。
分析新的积性函数求和的时候,首先在确认积性之后,分析单个素数的函数值,然后分析素数的a次方积性函数值,得出线筛方程。
完整代码:
#include<stdio.h>typedef long long dnt;const int N=1e7+10;const int mod=1e9+7;int primes[N],isnot[N],ptot=0;dnt other[N],mpk[N],mpr[N],f[N],ans=0;dnt quickmub(dnt a,dnt b){ dnt rt=1; while(b) { if(b&1) rt=(rt*a)%mod; a=(a*a)%mod,b>>=1; } return rt;}dnt fix(dnt a){ return (a%mod+mod)%mod;}void init(int n){ isnot[1]=1,f[1]=1; for(register int i=2;i<=n;i++) { if(!isnot[i]) { primes[ptot++]=i; mpr[i]=i,mpk[i]=1,other[i]=1; f[i]=fix(2-i); } for(register int t=0;t<ptot;t++) { int j=primes[t]*i; if(j>n) break ; isnot[j]=1; other[j]=i,mpr[j]=primes[t],mpk[j]=1; f[j]=f[i]*fix(2-primes[t])%mod; if(i%primes[t]==0) { other[j]=other[i]; mpr[j]=primes[t],mpk[j]=mpk[i]+1; f[j]=f[other[i]]*fix(mpk[j]+1-mpr[j]*mpk[j])%mod; break ; } } }}int main(){ freopen("facsum.in","r",stdin); freopen("facsum.out","w",stdout); int n,m; scanf("%d%d",&n,&m); init(n); for(int i=1;i<=n;i++) ans=(ans+quickmub(i,m)*f[i]%mod)%mod,ans=fix(ans); printf("%I64d\n",ans); return 0;}
今天算是早的学到了,原来觉得反正不是正解,为什么要验证?然后今天就死在没有验算打表的暴力上orz。
不管是正解,还是暴力,该验证的一定得验证,不然GG,不能偷懒
2。
这道题,简直是裸的求阶
一开始没看到a,mod互质,想了好久
然后直接就写出来了
题目就是求最小的b使得 a^b mod m == 1
特判0然后BsGs拔山盖世大步小步阿姆斯特朗算法求解即可
注意特判m==1的情况
完整代码:
#include<stdio.h>#include<cstring>#include<math.h>using namespace std;typedef long long dnt;const dnt S=76543;struct HASH{ dnt head[S],num; struct edge { dnt a,b; int last; }ed[S*2]; void init() { num=0; memset(head,0,sizeof(head)); } void insert(dnt a,dnt b) { dnt key=a%S; for(int i=head[key];i;i=ed[i].last) if(ed[i].a==a) return ; num++; ed[num].a=a,ed[num].b=b; ed[num].last=head[key]; head[key]=num; } dnt query(dnt a) { dnt key=a%S; for(int i=head[key];i;i=ed[i].last) if(ed[i].a==a) return ed[i].b; return -1; }}hash;dnt exgcd(dnt a,dnt b,dnt &x,dnt &y){ if(b==0) { x=1,y=0; return a; } dnt x0,y0; dnt d=exgcd(b,a%b,x0,y0); x=y0; y=x0-a/b*y0; return d;}dnt inverse(dnt a,dnt m){ dnt x,y; dnt d=exgcd(a,m,x,y); if(d!=1) return -1; return (x%m+m)%m;}dnt BsGs(dnt a,dnt b,dnt m){ hash.init(); dnt c=(dnt) sqrt((double) m),cur=1; for(int i=0;i<c;i++,cur=(cur*a)%m) { if(b==cur && i!=0) return i; hash.insert(cur,i); } dnt base=inverse(cur,m); if(base==-1) return -1; cur=(b*base)%m; for(dnt i=c;i<=m;i+=c,cur=(cur*base)%m) { dnt tmp=hash.query(cur); if(tmp!=-1) return tmp+i; } return -1;}int main(){ freopen("group.in","r",stdin); freopen("group.out","w",stdout); int T; dnt n,mod; scanf("%d",&T); while(T--) { scanf("%I64d%I64d",&n,&mod); if(n==1 || mod==1) printf("1\n"); else printf("%I64d\n",BsGs(n,1,mod)); } return 0;}/*12 5*/
对付这种一眼题也要万分小心才好,今天这道题一开始想到了两种思路,然后写了两份代码互相对了好久的拍才算放心
3。
这道题是真的没思路啊
因为题意看起来比较简单就想了好久,
最后实在没办法只能暴力Lucas水过去了。。。
得分40
姑且听了一下正解。。
什么?5进制拆分?数位DP?组合数?EXM?
正解其实若是知道Lucas本来的性质或者说证明方法和实现原理这道题其实不难想到
但是记得当年学Lucas的时候耳畔一直回响着某大佬的一句
“信息学奥赛没有证明”
Lucas一直是背板子
Lucas其实就是按照mod数进制拆分,去进制下每一位的组合数在累乘起来
那么要想一个数最后的组合数mod 5 为0,只需要在任意一位的组合数位0就行了
那么问题就转换成了L到R在5进制下有至少一位的组合数为0的数的个数
在5进制下数位DP即可
完整代码:
#include<stdio.h>#include<cstring>using namespace std;typedef long long dnt;const int mod=5;int T,a[100010],num[100010];dnt saber[100010],inv[100010],f[100010][2];void init(int n){ saber[0]=inv[0]=inv[1]=1; for(int i=1;i<=n;i++) saber[i]=saber[i-1]*i%mod; for(int i=2;i<=n;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; for(int i=1;i<=n;i++) inv[i]=inv[i-1]*inv[i]%mod;}dnt Misaka(dnt a,dnt b){ if(a<b) return 0; if(a<mod) return saber[a]*inv[b]%mod*inv[a-b]%mod; return Misaka(a/mod,b/mod)*Misaka(a%mod,b%mod);} void sov1(int L,int R,int n){ dnt ans=0; for(int i=L;i<=R;i++) ans+=(Misaka(n,i)==0); printf("%d\n",ans);}dnt dfs(int pos,int pre,int lim){ if(pos==-1) return pre; if(!lim && f[pos][pre]!=-1) return f[pos][pre]; dnt ans=0; int up=lim ? a[pos] : 4; for(int i=0;i<=up;i++) ans+=dfs(pos-1,(pre || Misaka(num[pos],i)==0),i==up && lim); if(!lim) f[pos][pre]=ans; return ans;}dnt solve(dnt n){ int cnt=0; memset(a,0,sizeof(a)); while(n) { a[cnt++]=n%5; n/=5; } return dfs(cnt-1,0,1);}void Divide(dnt n){ int cnt=0; memset(num,0,sizeof(num)); while(n) { num[cnt++]=n%5; n/=5; }}void sov2(dnt L,dnt R,dnt n){ Divide(n); memset(f,-1,sizeof(f)); dnt ans=solve(R)-solve(L-1); printf("%I64d\n",ans);}int main(){ freopen("ccount.in","r",stdin); freopen("ccount.out","w",stdout); init(5); scanf("%d",&T); while(T--) { dnt L,R,n,ans=0; scanf("%I64d%I64d%I64d",&L,&R,&n); if(R-L+1<=5000) sov1(L,R,n); else sov2(L,R,n); } return 0;}
今天算是明白了Lucas定理的时间原理了
果然如YYR学长所说,算法原理还是很重要啊~~~
今天考试的成绩就在倒好不好的环境中落幕了
明天ACM,队友都还没定orz,加油吧~~~
嗯,就是这样
- NOIP 2017.10.20 总结+心得
- NOIP 2017.10.3 总结+心得
- NOIP 2017.10.4 总结+心得
- NOIP 2017.10.23 总结+心得
- NOIP 2017.10.24 总结+心得
- NOIP 2017.10.27 总结+心得
- NOIP 2017.9.17 总结+心得
- NOIP模拟2017.9.19 总结+心得
- NOIP模拟赛2017.9.11 考试心得+总结
- NOIP模拟 2017.10.4 总结
- 14.9.20 Noip总结?反思
- noip总结
- NOIP总结
- NOIP总结
- NOIP总结
- NOIp总结
- 论蒟蒻是怎样作死的(noip模拟赛心得&易错总结)
- 2017.10.11 noip模拟赛 总结
- Linux上安装pyTorch
- 【Leetcode-Medium-647】Palindromic Substrings
- Android N 7.0 应用间共享文件(FileProvider)
- 独立任务最优调度(双机调度)问题
- 洛谷 1083||NOIP 2012 借教室 二分答案+差分 解题报告
- NOIP 2017.10.20 总结+心得
- urlencode/base64/sha1/md5学习
- Hololens之固定语音命令总结
- win10配置TensorFlow GPU出现Failed to load the native TensorFlow runtime."
- 【Deep Learning】BP网络手写识别
- 简析String --StringBuffer--StirngBuilder
- 论文笔记:Personalized Deep Learning for Tag Recommendation
- Scrapy学习笔记(2)分布式爬虫
- memcache的安装和使用步骤