码迷,mamicode.com
首页 > 其他好文 > 详细

铁板铮铮♂+习题集

时间:2018-09-24 16:50:01      阅读:201      评论:0      收藏:0      [点我收藏+]

标签:卡特兰数   sed   while   att   排序   取数   辗转相除法   iostream   noip   

 

数论

  • 快速幂

当b为偶数:ab=ab/2 * ab/2

当b为奇数:ab=ab/2 * ab/2 * a

核心代码:

技术分享图片
ll quickpow(ll a,ll b)
{       
    ll ret=1;
    while(b)
    {
        if(b%2==1)
        ret=ret*a%P;
        a=a*a%P;
        b/=2;
    }
    return ret;
}
View Code

 

 

习题集
题目号 题目名 注释
洛谷P1965 【NOIP2013TG】转圈游戏 简单推导公式
洛谷P3197

【HNOI2008】越狱

与组合数学结合+容斥

 

 

 

 

 

  • 线性筛

技术分享图片
#include<iostream>
using namespace std;
#define maxn 10000001
int prime[maxn],v[maxn],f[maxn];//prime为素数表
                                //v为每个数的最小质因子 
                                //f数组判断是否是素数 
int n,m,k;
void primes(int n)
{
    k=0;
    for(int i=2;i<=n;i++)//从2开始 
    {
        if(v[i]==0) 
        {
            v[i]=i;//i是质数,则i的最小质因子为本身 
            prime[++k]=i;
            f[i]=1;
        }
        for(int j=1;j<=k;j++)
        {
            if(prime[j]>v[i]||prime[j]*i>n) break;
            //如果i有比prime[j]更小的质因子
            //或者超出n的范围 
            v[i*prime[j]]=prime[j];//prime[j]是合数i*prime[j]的最小质因子 
        }
    }
}
int main()
{
    cin>>n>>m;
    primes(n);
    for(int i=1;i<=m;i++)
    {
        int x;
        cin>>x;
        if(f[x]==1)
        cout<<"Yes"<<endl;
        else
        cout<<"No"<<endl;
    }
}
View Code
习题集
题目号 题目名 注释
洛谷P3383 线性筛素数 模板题
洛谷P2926 【USACO08DEC】Patting Heads  特殊筛法
Codeforces 776B Sherlock and his girlfriend  特判+筛法

 

 

 

 

 

  • 质因数分解

技术分享图片
void divide(int x)
{
    m=0; 
    for(int i=2;i*i<=n;i++)//一个数至多只有一个大于根号n的质因子
                           //所以后面特判 前面只要到根号n 
    {
        if(n%i==0)//i是质数 
        {
            p[++m]=i;
            c[m]=0;
        }
        while(n%i==0)
        {
            n=n/i;//除掉所有的i 
            c[m]++; //i的指数加1 
        }
    }
    if(n>1)//特判大于根号n的那个 
    {
        p[++m]=n;
        c[m]=1; 
    }
}
View Code
习题集
题目号 题目名 注释
洛谷P1075 【NOIP2012PJ】质因数分解 模板题
洛谷P1463 【HAOI2007】反素数  搜索+约数个数

 

 

 

 

 

 

  • gcd与lcm

辗转相除法求gcd

技术分享图片
int gcd(int a,int b)
{
    if(b==0)
    return a;
    else return gcd(b,a%b);
}
View Code

求lcm:

a*b=gcd(a,b)*lcm(a,b)

习题集
题目号 题目名 注释
 洛谷P1072 【NOIP2009TG】Hankson的趣味题   推导

 

 

 

 

  • 扩展欧几里得exgcd

技术分享图片
void exgcd(int a,int b,int &d,int &x,int &y)
{
    int t;
    if(b==0)//当b=0时 gcd(a,b)=a
            //因为1*a+0*0=a 所以ax+by=gcd(a,b)有一组解为
            //x=1 y=0 
    {
        d=a;
        x=1;
        y=0; 
    }
    else
    {
        exgcd(b,a%b,d,x,y);
        t=x;//推导得公式 
        x=y;
        y=t-(a/b)*y;
    }
}
View Code
习题集
题目号 题目名 注释
洛谷P1516 青蛙的约会  简单推导公式
洛谷P1082 【NOIP2012TG】同余方程  模板题
洛谷P2421 【NOI2002】荒岛野人 推导公式+条件判断

 

 

 

 

 

  • 乘法逆元

 对于a/b mod p(b和p互质)

First 费马小定理:

如果b和p互质 则bp≡b(mod p)

由此可得bp-1≡1(mod p) 结合求逆元方程b*x≡1(mod p) 得到bp-1≡b*x(mod p)

所以x≡bp-2(mod p)结合快速幂求出x

技术分享图片
#include<cstdio> 
#define ll long long
using namespace std;
int n,p;
inline ll ksm(ll a,ll b){
    ll ans=1;
    a%=p;
    while(b){
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans%p;
}
void write(ll x){
    if(x<0) putchar(-),x=-x;
    if(x>9) write(x/10);putchar(x%10^48);
}
int main(){
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;i++)
        write(ksm(i,p-2)),putchar(\n);
    return 0;
}
View Code

Second 解不定方程

解a*x≡1(mod p)等于解ax+py=1 

因为p是质数 所以gcd(a,p)=1;

即解ax+py=gcd(a,p) 用exgcd解x

技术分享图片
#include<cstdio>
using namespace std;
int x,y;
void exgcd(int a,int b){
    if(!b){x=1,y=0;return ;}
    exgcd(b,a%b);
    int t=x;
    x=y,y=t-a/b*y;
}
void write(int x){
    if(x>9) write(x/10);
    putchar(x%10^48);
}
int main(){
    int n,p;
    scanf("%d%d",&n,&p);
    for(int i=1;i<=n;++i)
        exgcd(i,p),write((x%p+p)%p),putchar(\n);
    return 0;
}
View Code

Third 线性递推

技术分享图片
#include<cstdio>
#define ll long long
using namespace std;
const int maxn=3e6+5;
ll inv[maxn]={0,1};
int main(){
    int n,p;
    scanf("%d%d",&n,&p);
    printf("1\n");
    for(int i=2;i<=n;i++)
        inv[i]=(ll)p-(p/i)*inv[p%i]%p,printf("%d\n",inv[i]);
    return 0;
}
View Code
习题集
题目号 题目名 注释
POJ1845 Sumdiv  约数和+模板

 

 

 

  • 中国剩余定理

对于多个x≡ai(mod mi)

M=∏ni=1mi    Mi=M/mi

ti是线性同余方程Mi*ti≡1(mod mi)的一个解

x=∑ni=1ai*Mi*ti

技术分享图片
int intchina(int n)
{
    int Mi,x,y,d,ans=0;
    M=1;
    for(int i=1;i<=n;i++)
    M*=m[i];
    for(int i=1;i<=n;i++)
    {
        Mi=M/m[i];
        exgcd(Mi,m[i],d,x,y);
        ans=(ans+Mi*x*a[i])%M;
    }
    return (ans+M)%M;
} 
View Code
习题集
题目号 题目名 注释
洛谷P1495 曹冲养猪  模板题
UVA756 Biorhythms 模板+特殊解

 

 

 

  • Lucas定理

技术分享图片
#include<iostream>
#include<cstdio>
using namespace std;
#define LL long long
LL T,n,m,p;
LL quickpow(LL a,LL b)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=ret*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ret;
}
LL C(LL n,LL m)
{
    if(m>n) return 0;
    LL a=1,b=1;
    for(LL i=n-m+1;i<=n;i++)
    a=a*i%p;//计算n!/(n-m)! 
    for(LL i=2;i<=m;i++)
    b=b*i%p;//计算1/m! 
    return a*quickpow(b,p-2)%p;//费马小定理求逆元 
}
LL Lucas(LL n,LL m)
{
    if(!m) return 1;
    else return (C(n%p,m%p)*Lucas(n/p,m/p))%p;//递推公式 
}
int main()
{
    scanf("%lld",&T);
    while(T)
    {
        T--;
        scanf("%lld%lld%lld",&n,&m,&p);
        printf("%lld\n",Lucas(n,m));
    }
}
View Code
习题集
题目号 题目名 注释
洛谷P3807 卢卡斯定理 模板题

 

 

 

  • 组合排列问题

组合:A(n,m)=n(n-1)*(n-2)*……*(n-m+1)= n!/(n-m)!

排列:C(n,m)=A(n,m)/m!=n!/(m!(n-m)!)

习题集
题目名 题目号 注释
洛谷P1066 【NOIP2006TG】2^k进制数 复杂高精+组合推导(有点难)
洛谷P2822 【NOIP2016TG】组合数问题   二维前缀和+杨辉三角
洛谷P1350 车的放置 推导矩阵公式
洛谷P3166 【CQOI2004】数三角形 组合+GCD
洛谷P2532 【AHOI2012】树屋阶梯 卡特兰数+高精
洛谷P3200 【HNOI2009】有趣的数列 卡特兰数+质因数分解
洛谷P1375 小猫 卡特兰数+逆元

 

 

 

 

 

 

 


 

动态规划

  • 区间DP

枚举所有在i与j之间的k

把一段区间分成两段为两个状态

如果是环形可以考虑断环成链 开数组2n

初始化 f[i][i]=1或者权值

答案要枚举所有的左端点到后n位

核心代码:

技术分享图片
     f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]+sum[j]-sum[i-1]);
        f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]+sum[j]-sum[i-1]);
View Code
习题集
题目号 题目名 注释
洛谷P1880 【NOI1995】石子合并 断链成环
洛谷P1063 能量项链 中等难度
洛谷P2426 删数 从两边删除区间
洛谷P3146 【USACO160PEN】248 类似2048游戏
洛谷P1005 【NOIP2007TG】矩阵取数游戏  高精+翻倍
洛谷P3205 【HNOI2010】合唱队 用两个数组

 

 

 

 

 

 

 

 


 

图论

  • 并查集:

技术分享图片
#include<iostream>
using namespace std;
int father[5001];
int n,m,p;
int find(int x)
{
    if(father[x]!=x)//路径压缩优化
    father[x]=find(father[x]);//把路上的所有点祖先全部改掉
    return father[x];
}
void unionn(int x,int y)
{
    father[y]=x;//y的祖先为x的祖先
                //相当于合并祖先
}
int main()
{
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++)
    {
        father[i]=i;//所有数据初始祖先为自己
                    //独立的一个数为一个集合
    }
    for(int i=1;i<=m;i++)
    {
        int x,y;
        cin>>x>>y;
        int r1,r2;
        r1=find(x);
        r2=find(y);//寻找两个数的祖先
        if(r1!=r2)//如果不是同一个祖先
        {
            unionn(r1,r2);//合并
        }
    }
    for(int i=1;i<=p;i++)
    {
        int x,y;
        cin>>x>>y;
        if(find(x)==find(y))//如果是同一个祖先
        {
            cout<<"Yes"<<endl;//
        }
        else
        cout<<"No"<<endl;//
    }
    
}
View Code
习题集
题目号 题目名 注释
洛谷P3367 【模板】并查集 如题
洛谷P2024

【NOI2001】食物链

搞好三者关系

洛谷P1525

关押罪犯

排序+并查集

洛谷P1111

修复公路

eazy

洛谷P1197

【JSOI2008】星球大战

逆向思维

 

 

 

 

 

 

 

 

 

  • 最小生成树:

Kruskal

技术分享图片
#include<iostream>
#include<algorithm>
using namespace std;
struct edge
{
    int l,r,w;//左端点 右端点 权值 
}e[200001];
int father[5001];
int n,m,k=0,tot;
bool cmp(const edge &a,const edge &b)//用权值排序 
{
    if (a.w<b.w) return 1;
    else return 0;
}
int find(int x)
{
    if(father[x]!=x)
    father[x]=find(father[x]);
    return father[x];
}
void unionn(int x,int y)
{
    int fa=find(x);
    int fb=find(y);
    if(fa!=fb)
    father[fa]=fb;
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    father[i]=i;
    for(int i=1;i<=m;i++)
    {
        cin>>e[i].l>>e[i].r>>e[i].w;
    }
    sort(e+1,e+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        if(find(e[i].l)!=find(e[i].r))
        {
            unionn(e[i].l,e[i].r);
            tot+=e[i].w;
            k++;
        }
        if(k==n-1) break;//到n-1条时退出 
    }
    cout<<tot;
}
View Code
习题集
题目号  题目名 注释
洛谷P3366 【模板】最小生成树 如题
洛谷P1195 口袋的天空 处理边的关系
洛谷P2330 【SCOI2005】繁忙的都市 记下最大值

 

 

 

 

 

  • 强连通分量:

Tarjan

技术分享图片
void Tarjan(int u)
{
    dfn[u]=low[u]=++num;
    st[++top]=u;//入栈
    vis[u]=1;//判断是否在栈中 
    for(int i=h[u];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            Tarjan(v);
            low[u]=min(low[u],low[v]);//low表示u与其子孙到达的最小编号 
        }
        else 
        if(vis[v])//判断v是否在栈中
        low[u]=min(low[u],dfn[v]);
        //可以改成 min(low[u],low[v])
        //因为此时v的low和dfn还未修改 
    }
    if(dfn[u]==low[u])
    {
        co[u]=++col;//属于第col个强连通分量 
        while(st[top]!=u)
        {
            co[st[top]]=col;
            vis[st[top--]]=0;
        }
        --top;
    }
}
View Code
习题集
题目号 题目名 注释
洛谷P2341 [HAOI2006]受欢迎的牛 缩点+小思想

铁板铮铮♂+习题集

标签:卡特兰数   sed   while   att   排序   取数   辗转相除法   iostream   noip   

原文地址:https://www.cnblogs.com/BrokenString/p/9462209.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!