noip_最后一遍_1-数学部分

它就是要来了

noip数论一般会以三种形式呈现

注 码风可能有些毒 (有人说我压行qwq) 大概保持标准三十五行左右 

为什么是三十五行呢 因为我喜欢这个数字 我喜欢三十五而已(足球球衣也会用这个号哒)

1.结论规律与打表技巧

这类的题最杰出的代表是小凯的疑惑

打表技巧的话主要是研究三个要点

1.一个输入数据和模数时

oeis这个时候最好用了 不过没有

我们需要重点研究的是递推关系,差,二阶差这样

这时候我们会发现三类数据

· 等差等比二阶等差二阶等比等差等比………………这种都是有通项的 考验数学能力

· 与二进制和唯一分解定理有关 

这个内容多 展开说

lowbit 1,2,1,3,1,2,1,4,1,2,1,3,1,2,1,5…………这个东西太常见了 不就是x&(-x)么 好的 可以开始考虑o n 数学方法比如化简Σ之类的

唯一分解定理目前我所见都很天然的 一眼就能看出来 

二进制的1个数 这个东西是个阶梯状函数 所以也是比较容易找到规律的 至于如何统计 大概只能枚举位数

· 递推-这个时候就看一下数据 如果小或者递推关系复杂 就考虑dp与暴力枚举,否则上矩阵(一定要注意一下)

2.两到三个数据 没什么办法 直接找

3.一行数据(那其实是不等式和贪心)排序值 均值大概率在考纲之中 柯西的话我想没那么好出

本部分需要用的模板 所有代码最新手打测试无误可以使用

1.快速幂、快速乘

快速幂 :a^p-2=a^(-1)(modp);

 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 #define ll long long
 5 using namespace std; 
 6 ll n,k,x,a,b;
 7 ll ksc(ll a,ll b,ll p){ll ans=0,base=a;
 8     for(;b;b>>=1){if(b&1)ans+=base,ans%=p;
 9         base*=2,base%p;
10     }return ans;
11 }
12 int main(){cin>>a>>b>>n;
13     cout<<ksc(a,b,n)<<endl;
14 }
View Code
#include<iostream>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std; 
ll n,k,x,a,b;
ll ksm(ll a,ll x,ll p){ll ans=1,base=a;
    for(;x;x>>=1){if(x&1)ans*=base,ans%=p;
        base*=base,base%p;
    }return ans;
}
int main(){cin>>a>>b>>n;
    cout<<ksm(a,b,n)<<endl;
}
View Code

2.线性筛素数 phi mu

 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 #define ll long long
 6 #define maxn 5000001
 7 bool isprime[maxn];int n,m,sum=0,prime[maxn];
 8 void shai(){
 9     for(int i=2;i<maxn;i++){
10         if(!isprime[i])prime[sum++]=i;
11         for(int j=0;j<sum&&i*prime[j]<maxn;j++){
12             isprime[i*prime[j]]=1;if(i%prime[j]==0)break;
13         }
14     }
15 }int main(){
16     cin>>n;shai();for(int i=0;i<=n;i++)cout<<prime[i]<<" ";
17 }
View Code
 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 #define ll long long
 6 #define maxn 5000001
 7 bool isprime[maxn];int n,m,sum=0,prime[maxn],phi[maxn];
 8 void shai(){phi[1]=1,phi[2]=1; 
 9     for(int i=2;i<maxn;i++){
10         if(!isprime[i])prime[sum++]=i,phi[i]=i-1;
11         for(int j=0;j<sum&&i*prime[j]<maxn;j++){
12             isprime[i*prime[j]]=1;phi[i*prime[j]]=phi[i]*(prime[j]-1);
13             if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];break;}
14         }
15     }
16 }int main(){
17     cin>>n;shai();for(int i=0;i<=n;i++)cout<<phi[i]<<" ";
18 }
View Code
 1 #include<iostream>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5 #define ll long long
 6 #define maxn 5000001
 7 bool isprime[maxn];int n,m,sum=0,prime[maxn],phi[maxn],mu[maxn];
 8 void shai(){phi[1]=1,phi[2]=1;mu[1]=1; 
 9     for(int i=2;i<maxn;i++){
10         if(!isprime[i])prime[sum++]=i,phi[i]=i-1,mu[i]=-1;
11         for(int j=0;j<sum&&i*prime[j]<maxn;j++){
12             isprime[i*prime[j]]=1;phi[i*prime[j]]=phi[i]*(prime[j]-1);mu[i*prime[j]]=-mu[i];
13             if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j],mu[i*prime[j]]=0;break;}
14         }
15     }
16 }int main(){
17     cin>>n;shai();for(int i=0;i<=n;i++)cout<<mu[i]<<" ";
18 }
View Code

3.数论分块 这是个技巧……

4.矩阵快速幂

 这个有点烦的是一直dev调试这个会出大问题 好像就是dev5.4.2的bug一样

他在调试时会自己死机 一会又好了 有时候烦的一批 鬼使一

并且奇特的是新建矩阵居然不会自动清空这就很奇特

可能是个大bug 5.4.2的版本会出这个问题 考试时候可能是5.4.2 所以说解决办法就只有一个 一遍打对,每次新建memset

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxn 105
 5 #define mod 1000000007
 6 struct matrix{ll a[maxn][maxn],len,row;}m1;ll n,m,k,l;
 7 matrix jc(matrix a,matrix b){
 8 matrix now;now.len=b.len,now.row=a.row;memset(now.a,0,sizeof(now.a));
 9     for(int i=1;i<=a.row;i++){
10         for(int j=1;j<=b.len;j++){
11             for(int k=1;k<=a.len;k++){
12                 now.a[i][j]+=a.a[i][k]*b.a[k][j],now.a[i][j]%=mod;
13             }
14         }
15     }return now;
16 }matrix ksm(matrix a,ll x){
17     matrix base=a,ans;ans.len=a.len,ans.row=a.row;memset(ans.a,0,sizeof(ans.a));
18     for(int i=1;i<=a.len;i++)ans.a[i][i]=1;
19     for(;x;x>>=1){
20         if(x&1)ans=jc(ans,base);
21         base=jc(base,base);
22     }return ans;
23     
24 }
25 int main(){cin>>n>>k;m1.len=m1.row=n;
26     for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)cin>>m1.a[i][j];
27     m1=ksm(m1,k);
28     for(int i=1;i<=n;i++){for(int j=1;j<=n;j++)cout<<m1.a[i][j]<<" ";
29     cout<<endl;}return 0;
30 }
View Code

5.二进制 这也是技巧 没有代码

这一类题大概也就这样 真的出来了什么鬼题也没办法

2.正宗数论

其实有意思的一匹 很有意思

1.带余除法为核心 

·逆元线性递推

设 t=ki+b;求t^(-1)

图片出处-guessycb暗中给了我许多 十分感谢

 1 #include<iostream>
 2 using namespace std;
 3 #define maxn 5000005
 4 #define ll long long
 5 ll n,m,p,f[maxn];
 6 int main(){cin>>n>>p;
 7     f[1]=1;for(int i=2;i<=n;i++){
 8         f[i]=(p-p/i)*f[p%i]%p;
 9     }for(int i=1;i<=n;i++)printf("%lld\n",f[i]);
10 }
View Code

2.唯一分解定理为核心 这个都知道就是什么因子和因子个数 有的时候你以为很暴力 不过由于那个基本时间复杂度定理 它是跟n的或者log的或者on的

3.exgcd为核心

这个大概有两类出法 1.青蛙的约会——荒野猎人 这两个基本是必做题吧 ab可不互质啊

求同余方程解 a=b(modc)->ax+cy=b; (a,c)=d;

有ax0+cy0=1 x=(x0*(b/d)+p)%p*c  此处p为x取值周期

第二类 关于gcd、lcm 那个乘积代换式一定不会单独考 因为太low

gcd这个物质它不但可以与exgcd建立莫大的联系 还可以维系phi mu 莫比乌斯反演 那种东西其实很套路 有趣的一匹

跟exgcd的时候  我们熟知 m(a,b)=(ma,mb)=m(a+b,b)这样就是他 还真有这么几道题

4.crt 一张图

 

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxn 1000005
 5 ll n,m[maxn],l,a[maxn],t[maxn],M=1,k[maxn],ans=0;
 6 void exgcd(ll a,ll b,ll &x,ll &y){
 7     if(!b){x=1,y=0;return ;}
 8     exgcd(b,a%b,y,x);y-=a/b*x;
 9 }
10 ll qpow(ll a,ll x,ll p){ll ans=1,base=a;
11     for(;x;x>>=1){
12         if(x&1)ans=ans*base%p;
13         base=base*base%p;
14     }return ans;
15 }
16 int main(){
17     cin>>n;
18     for(int i=1;i<=n;i++)cin>>a[i]>>m[i],M*=m[i];
19     for(int i=1;i<=n;i++){t[i]=M/m[i];exgcd(t[i],m[i],k[i],l);
20     k[i]=(k[i]%m[i]+m[i])%m[i];
21     ans=(ans+a[i]*t[i]*k[i])%M;
22     }cout<<ans<<endl;
23 }
View Code

 

5.卢卡斯 它的本质是模数意义下的c 配合crt求出原始值(古代猪文)

 

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<cmath>
 5 using namespace std;
 6 #define ll long long
 7 #define maxn 300005
 8 ll f[maxn],inv[maxn],n,m,k,p;
 9 ll qpow(ll a,ll x,ll p){ll ans=1,base=a;
10     for(;x;x>>=1){
11         if(x&1)ans=ans*base%p;base=base*base%p;
12     }return ans;
13 }
14 ll c(ll n,ll m,ll p){if(m<n)return 0;
15     ll a=qpow(f[n],p-2,p),b=qpow(f[m-n],p-2,p);
16     return f[m]*a*b%p;
17 }
18 ll lucas(ll n,ll m,ll p){
19     if(!n)return 1;
20     return c(n%p,m%p,p)*lucas(n/p,m/p,p)%p;
21 }
22 int main(){cin>>k;
23     while(k--){
24         cin>>n>>m>>p,f[0]=1;
25         for(int i=1;i<maxn;i++)f[i]=f[i-1]*i%p;
26         cout<<lucas(n,n+m,p)<<endl;
27     }
28 }
View Code

 

6.欧拉定理和马小

有个题叫a^b^c%p

这个东西怎么求呢 就是欧拉定理 a^b=a^((b%phi[p])+phi[p])(modp)但是需要特判

(1)当n>1,(a,n)=1时, a^b%n=a^b%φ(n)%n
(2)当bφ(n)时,直接计算即可。
(3)当b>φ(n)时 , 刚才的式子

7.phi的用法

几个零碎的点

·观察者问题

·互质对 这个说一下 求Σ(1-n)Σ(1-m)【gcd(i,j)==1】是那个莫反套路

刻意背过也可以 ∑    i=1-n∑   j=1-m   [gcd(i,j)=1]  =∑  i=1-n  μ(i)  n/im/i

如果把第二个m变成n就大不一样了

对于1每个n(1-n)与他互质且比他小(避免算重)的个数就是phi【i】

·母函数与二项式定理

考过二项式定理裸题 母函数的话主要是求 一个奇怪的组合数 然后对函数加减

不过noip不太会考它

3.几何和组合

数学的话还要看一手几何和组合数学

有点相同 所以一起看一手

组合——几个方法

·隔板法 要求划分出非空k集 =c(k,n+1)有空集一样 等于每个集合多个元素罢了

·折线法 其实是组合和坐标的加和

(1,1)-》(n,m)方案=c(n,n+m);

然后 我们考虑一种到达目标点且不经过固定几何图形的方案数

其实就是容斥,目标点关于几何图形对称 方案数就是相减

·高级容斥 想清楚要求什么 什么好求

 几何

·矢量叉积-求面积 夹角

·矢量旋转

已知任意一个平面向量ab=(x,y) ,把向量ab绕其起点沿逆时针方向旋转a角得到向量AP=(xcosa-ysina,xsina+ycosa)

一堆操作 在这个板子里 还有就是旋转九十度什么的就直接搞点就行 向量用不着

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n;double ans,m;
 4 struct node{double x,y;}a[1000005];
 5 node add(node a,node b){node c;c.x=a.x+b.x,c.y=a.y+b.y;return c;}//+
 6 node niadd(node a,node b){node c;c.x=a.x-b.x,c.y=a.y-b.y;return c;}//-
 7 
 8 double dot(node a,node b){return a.x*b.x+a.y*b.y;}//· 
 9 double cha(node a,node b){return a.x*b.y-a.y*b.x;}//*
10 
11 double len(node a){return sqrt(a.x*a.x+a.y*a.y);}// |a|
12 double squ(){ // S
13     for(int i=1;i<n;i++)ans+=(double)cha(a[i],a[i+1])/2;
14     ans+=(double)cha(a[n],a[1])/2;
15     return fabs(ans);
16 }
17 double geta(node a,node b){//获得小夹角cos值 
18     return dot(a,b)/(len(a)*len(b));
19 }
20 node rotate(node a,double coss){//旋转arccosa度(正向)(逆时针) 
21     double sins=sqrt(1-coss*coss);
22     node c;c.x=a.x*coss-a.y*sins,c.y=a.x*sins+a.y*coss;
23     return c;
24 }
25 double angle(double cosa){
26     return acos(cosa);
27 }
28 
29 node adjust(node a,double b){
30     a.x*=b/len(a),a.y*=b/len(a);return a;
31 }
32 int main(){
33     cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i].x>>a[i].y;
34     printf("%.4f\n",squ()*(double)m);
35 }
View Code

·凸包

这个真的捞 因为手打队列具有无比的优势 就是他需要访问栈顶第二个元素 求出上凸壳然后怎么办呢 noip的话大概二分y轴会有机会考吧

还有就是凸包可以做直线的相交问题

尤其是相交+极值。

上几个板子

1.洛谷模板 叉积判断夹角正负

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstdio>
 4 #include<cmath>
 5 using namespace std;
 6 struct node{double x,y;}p[10005],s[10005];
 7 int n;double ans,mid;
 8 double CJ(node a1,node a2,node b1,node b2){
 9     return (a2.x-a1.x)*(b2.y-b1.y)-(b2.x-b1.x)*(a2.y-a1.y);
10 }
11 double dis(node p1,node p2){
12     return sqrt( (double)(p2.y-p1.y)*(p2.y-p1.y)*1.0+(double)(p2.x-p1.x)*(p2.x-p1.x)*1.0 );
13 }
14 bool cmp(node p1,node p2){
15     double tmp=CJ(p[1],p1,p[1],p2);if(tmp>0) return 1;
16     if(tmp==0 && dis(p[0],p1)<dis(p[0],p2)) return 1;
17     return 0;
18 }
19 
20 int main(){scanf("%d",&n);
21     for(int i=1;i<=n;++i){
22         scanf("%lf%lf",&p[i].x,&p[i].y);
23         if(i!=1&&p[i].y<p[1].y){
24             mid=p[1].y;p[1].y=p[i].y;p[i].y=mid;
25             mid=p[1].x;p[1].x=p[i].x;p[i].x=mid;
26         }
27     }
28     sort(p+2,p+1+n,cmp);s[1]=p[1];int tot=1;
29     for(int i=2;i<=n;i++){
30         while(tot>1&&CJ(s[tot-1],s[tot],s[tot],p[i])<=0) tot--;
31         tot++;s[tot]=p[i];
32     }s[tot+1]=p[1];
33     for(int i=1;i<=tot;i++) ans+=dis(s[i],s[i+1]);
34     printf("%.2lf\n",ans);return 0;
35 }
View Code

 

2.板子中的板子[HNOI2008]水平可见直线

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 50005
 4 #define ll long long
 5 ll n,m,k,a,b,c,s[maxn],top=0,ans[maxn];
 6 struct node{int k,b,id;}l[maxn];
 7 bool cmp(node a,node b){
 8     return a.k==b.k?a.b>b.b:a.k<b.k;
 9 }double getx(int a,int b){
10     return (double)(l[a].b-l[b].b)/(double)(l[a].k-l[b].k);
11 }
12 int main(){
13     cin>>n;for(int i=1;i<=n;i++)cin>>l[i].k>>l[i].b,l[i].id=i;
14     sort(l+1,l+n+1,cmp);
15     for(int i=1;i<=n;i++){
16         if(l[i].k==l[i-1].k&&i!=1)continue;
17         while(top>1&&getx(s[top],i)>=getx(s[top],s[top-1]))top--;
18         s[++top]=i;
19         ans[top]=l[i].id;
20     }sort(ans,ans+top+1);
21     for(int i=1;i<=top;i++)printf("%d ",ans[i]);
22 }
View Code

 

·三分

noip很可能在考纲里因为它就是二分的翻版。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 ll n,m,k;double a[30],l,r;
 5 double f(double pos){double ans=0;
 6     for(int i=1;i<=n+1;i++){
 7         ans+=pow(pos,n-i+1)*a[i];
 8     }return ans;
 9 }
10 double sanfen(double l,double r){
11     if(r-l<0.000001)return l;
12     double mid1=l+(r-l)/3,mid2=r-(r-l)/3;
13     if(f(mid1)>f(mid2))return sanfen(l,mid2);
14     else return sanfen(mid1,r);
15 }
16 int main(){
17     cin>>n>>l>>r;
18     for(int i=1;i<=n+1;i++)cin>>a[i]; 
19     printf("%.5f",sanfen(l,r));
20 }
View Code

4.其他

细数了一下其实剩下的只有俩——高斯消元与行列式和线型基 要是考什么bsgs 就很烦了 不过bsgs还是看一看最好

另外什么牛顿迭代 matrixtree之类的谁知道他会不会灵性来一下 都发下

高消(行列式矩阵树都是对对角线矩阵求积)构造矩阵自己查吧 这个好像不属于板子(逃)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<cmath>
 7 #include<vecotr> 
 8 #define maxn 100
 9 using namespace std;
10 int n,m,k,l,a,b,c;
11 double mp[maxn][maxn];
12 int main(){
13     cin >> n;for(int i=1;i<=n;i++)
14         for(int j=1;j<=n+1;j++)
15             cin>>mp[i][j];   
16     for(int j=1;j<=n;j++){
17         int rgt=0;
18         for(int i=j;i<=n;i++)
19             if(mp[i][j]){rgt=i;break;}
20         if(!rgt)continue;
21         if(rgt^j)swap(mp[rgt],mp[j]);
22         
23         for(int i=j+1;i<=n;i++){
24             double div=mp[i][j]/mp[j][j];
25             for(int k=1;k<=n+1;k++)mp[i][k]-=div*mp[j][k];
26         }
27     }
28     for(int j = n; j >= 1; j --){
29         if(mp[j][j] == 0){cout<<"No Solution"; return 0;}
30         mp[j][n+1] =  mp[j][n+1] / mp[j][j];
31         for(int i = j-1; i >= 1; i --)mp[i][n+1] -= mp[j][n+1] * mp[i][j];
32     }
33     for(int i = 1; i <= n; i ++)printf("%.2lf\n" ,mp[i][n+1]);
34     return 0;
35 }
View Code

牛顿迭代求高次开跟

 1 #include<bits/stdc++.h>
 2 #define first 233.0
 3 #define ll long long
 4 #define ld double
 5 ld n,m,k,l,a,b,c,x;
 6 using namespace std;
 7 ll ksm(ll a,ll x){ll base=a,ans=1;
 8     for(;x;x>>=1){
 9         if(x&1)ans=base*ans;
10         base=base*base;
11     }
12     return ans;
13 }
14 int main(){
15     cin>>a>>m;x=first;
16     for(int i=1;i<=100;i++)x=x-x/m+a/((ld)1*m*ksm(x,m-1));
17     cout<<x<<endl;
18 } 
View Code

线型基

这个东西只有一种用处 求最大异或和

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 #define maxn 105
 5 ll n,m,k=0,l,s[maxn],a[maxn];
 6 void insert(ll x){
 7     for(int i=50;i>=0;i--){if(!x)return ;
 8         if((x&(1ll<<i))!=0){
 9             if(!s[i])s[i]=x;
10             x^=s[i];
11         }
12     }
13 }
14 int main(){
15     cin>>n;for(int i=1;i<=n;i++)cin>>a[i],insert(a[i]);
16     for(int i=50;i>=0;i--)if((k^s[i])>k)k^=s[i];
17     cout<<k<<endl;return 0;
18 }
View Code

那么数论基本结束了

高斯消元是薄弱点 第二次争取全对(其实有错更好)

祝rp++ 高分预定!!!

转载于:https://www.cnblogs.com/iboom/p/9905856.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值