• 【学习笔记】算法竞赛进阶指南第一章


    前言

    这是一篇流水账式的真·随笔

    大概是第n次被教做人过后,感受到了“菜是原罪”这句话的痛啊..于是决心补救一下,从啃书开始吧。

    觉得比较重要,是挑着着看的部分,会另开一篇总结的

    不得不说这本书真的挺有意思的!!!

    正文

    8.26

    看完了第一章,感觉懂了80%吧,应该写写题,看得还算认真,想了n遍都理解不到的地方基本都有勘误..

    8.27

    改完了考试的错,写写例题

    P4 POJ1995

    快速幂模板题

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    ll a,b,t,m,n,ans;
    ll ksm(ll a,ll b,ll mod)
    {
        ll ret=1;
        while(b)
        {
            if(b&1)ret=ret*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return ret;
    }
    int main()
    {
        scanf("%lld",&t);
        while(t--)
        {
            ans=0;
            scanf("%lld%lld",&m,&n);
            for(ll i=1;i<=n;i++)
            {
                scanf("%lld%lld",&a,&b);
                ans=(ans+ksm(a,b,m))%m;
            }    
            printf("%lld
    ",ans);
        }
    }

     P7

    状压太困难了,就写书上的部分,以后再填坑吧【按照自己写状压的习惯搞的..】

    /*
    本质是状压dp
    f[i][j]表示走到i点,状态为j(哪些点走过),w[i][j]表示i到j的路径长度
    则有f[i][j]=min{f[k][j^(1<<i)]+w[k][i]}
    */ 
    int cal(int n)
    {
        memset(f,0x3f,sizeof(f));
        f[0][1]=0;
        mx=(1<<n)-1;//最大状态 
        for(int i=1;i<n;i++)
            for(int j=0;j<=mx;j++)
                if(1&(j>>i))//走过i 
                    for(int k=0;k<n;k++)
                        if(1&(j>>k))//走过 k
                            f[i][j]=min(f[i][j],f[k][j^(1<<i)]+w[k][i]);
                            //要从k-->i必须满足i这个点在上一层状态里未被访问 
        return f[mx][n-1];
    }

    P9 TYVJ1266

    这题真的适合放枚举吗??我觉得挺坑的

    书上的思路看了几遍,没啥问题,但是真的不太好实现,也不知道怎么去一排一排推??

    8012年了,冥思无果当然是搜题解啊,被输入坑了半天,但是觉得这个题还挺有意思

    这个思路是用bfs,从全亮状态往回推,直到点了6次结束【其实bfs似乎才是最直接能想到的】,利用二进制存状态

    然而这个时空消耗都好大,严格地来说,状态上限有225    

    总之这个方法虽然思路简单,不需要数学证明也不需要深入思考,但的确不如书上的优..

    确实不知道怎么实现我也没办法啊

    一些解释在代码里

    #include<bits/stdc++.h>
    using namespace std;
    int o,t,mx,mp;
    int ans[1<<25];
    queue<int>q;
    /*
                k=0 
                ↓
                0 0 0 0 0 <--k=4
    k%5 == 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 <--k=19,k%5=4 0 0 0 0 0
    */ int read() { char ch=getchar(); while (ch<'0'||ch>'1') ch=getchar(); return ch-48; } inline int change(int x,int k) { x^=(1<<k);//当前位置 if(k>=5)x^=(1<<k-5);// if(k<20)x^=(1<<k+5);// if(k%5) x^=(1<<k-1);// if(k%5<4)x^=(1<<k+1);// return x; } void bfs() { memset(ans,-1,sizeof(ans)); mx=(1<<25)-1; q.push(mx);ans[mx]=0;//全亮状态不需要操作 while(!q.empty()) { int x=q.front();q.pop(); if(ans[x]==6)return; for(int i=0;i<25;i++) { int y=change(x,i); if(ans[y]<0)q.push(y),ans[y]=ans[x]+1; } } } int main() { scanf("%d",&t); bfs();//逆推 ,预处理所有情况需要操作次数 while(t--) { mp=0; for(int i=1;i<=5;i++) for(int j=1;j<=5;j++) { mp<<=1; mp+=read();//处理二进制地图,读入不要当做整数读,当字符串读! } printf("%d ",ans[mp]); } return 0; }

     P10

    水水的HANOI

    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<iostream>
    #include <queue>
    using namespace std;
    #define N 20
    int d[N],f[N];
    int main()
    {
        memset(f,0x3f,sizeof(f));
        d[1]=1;f[1]=1;
        for(int i=1;i<=12;i++)
            d[i]=2*d[i-1]+1;
        for(int i=1;i<=12;i++)
            for(int j=1;j<i;j++)
                f[i]=min(f[i],2*f[j]+d[i-j]);
        for(int i=1;i<=12;i++)
            cout<<f[i]<<endl;
    } 

    8.28 

    下午填完了两天考试的题解的坑,晚上才开始看书..

    P11 BZOJ1218

    二维前缀和,下标要从1开始..

    #include<bits/stdc++.h>
    using namespace std;
    #define N 5010
    int e[N][N],s[N][N];
    int n,x,y,v,r,mx,my,ans;
    int main()
    {
        scanf("%d%d",&n,&r);
        mx=r,my=r;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&x,&y,&v);
            x++;y++;
            e[x][y]=v;
            mx=max(x,mx);my=max(y,my);
        }
        for(int i=1;i<=mx;i++)
            for(int j=1;j<=my;j++)
                s[i][j]=s[i-1][j]+s[i][j-1]-s[i-1][j-1]+e[i][j];
        for(int i=r;i<=mx;i++)
            for(int j=r;j<=my;j++)
                ans=max(ans,s[i][j]-s[i-r][j]-s[i][j-r]+s[i-r][j-r]);
        printf("%d",ans);
        return 0;
    }

     P12 POJ3263

    这个题虽然水,但是思想很重要,写法也很有意思

    额外的总结:传送门

    #include<iostream>
    #include<cstdio>
    #include<map>
    #include<cstring>
    using namespace std;
    int n,p,h,m;
    #define N 10100
    map<pair<int,int>,bool>flag;
    int a[N],c[N],s[N];
    int main()
    {
        scanf("%d%d%d%d",&n,&p,&h,&m);
        for(int i=1;i<=m;i++)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            if(x>y)swap(x,y);
            if(flag[make_pair(x,y)])continue;
            c[x+1]--;c[y]++;
            flag[make_pair(x,y)]=1;
        }
        for(int i=1;i<=n;i++)
        {
            s[i]=s[i-1]+c[i];
            printf("%d
    ",s[i]+h);
        }
        return 0;
    }

     8.29

    临近开学,略慌。

    测试前看了一遍质数这一章。

    早上测试不算惨,于是先调了昨晚上留的坑

    P17 POJ1845

    数学题就是玄,本来想写分治,被安利了一种新的求逆元的方法,抱着尝试的心情去写,结果素数挂了,快速幂又挂了,开方也挂,总之惨不忍睹。各种奇怪的错误....

    不过这种求逆元方法确实也值得学习

    a/b%m=d

    a/b=mx+d

    a=bmx+bd

    a %bm=bd

    (a%bm)/b=d

    所以a除以b对m的取模,等效于a对b*m取模后除以b,很明显,非常适用于这种模数不大的情况。有几个坑点,比如开方向下取整,比如-1过后要再加上模数防止不是正数...

    #include<bits/stdc++.h>
    using namespace std;
    #define N 10100
    #define mod 9901
    #define ll long long
    ll prime[N],num,v[N];
    ll a,b,n,pos,cnt,mb,limit,ans=1;
    
    ll ksm(ll a,ll b,ll mb)
    {
        ll ret=1;
        a%=mb;
        while(b)
        {
            if(b&1)ret=ret*a%mb;
            a=a*a%mb;
            b>>=1;
        }
        return ret;
    }
    
    void primes()
    {
        for(ll i=2;i<N;i++)
        {
            if(!v[i])
            {
                v[i]=i;
                prime[++cnt]=i;
            }
            for(ll j=1;j<=cnt;j++)
            {
                if(prime[j]>v[i]||prime[j]*i>N)break;
                v[prime[j]*i]=prime[j];
            }
        }
    }
    
    int main()
    {
        scanf("%lld%lld",&a,&b);
         limit=sqrt(a)+1;n=a;primes();
        for(ll i=1;prime[i] * prime[i]<=n;i++)
        {
            if(n%prime[i]==0)
            {
                num=0;
                while(n%prime[i]==0)
                {
                    n/=prime[i];
                    num++;
                }
                mb=mod*(prime[i]-1);
                pos=ksm(prime[i],b*num+1,mb)+mb-1;
                ans*=pos/(prime[i]-1);
                ans%=mod;
                
            }
        }
        if(n>1)
        {
            mb=mod*(n-1);
            pos=ksm(n,b+1,mb)+mb-1;
            ans*=pos/(n-1);
            ans%=mod;
        }
        printf("%lld",ans);
        return 0;
    }

     真的讨厌信息处理,位置转换类的题,所以跳过了一道,现在留坑*2了...

    P26 POJ2018

    以前写过的二分,顺便复习了一下实数二分和整数二分的板..

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    #define N 100100
    #define INF 0x7fffffff
    #define eps 1e-5
    double a[N],b[N],s[N];
    double ans,minx,l,r,mid;
    int n,len;
    int main()
    {
        scanf("%d%d",&n,&len);
        for(int i=1;i<=n;i++)
            scanf("%lf",&a[i]);
        l=-1e6,r=1e6;
        while(r-l>eps)
        {
            ans=-INF,minx=INF;
            mid=(l+r)/2;
            for(int i=1;i<=n;i++)b[i]=a[i]-mid;
            for(int i=1;i<=n;i++)s[i]=s[i-1]+b[i];
            for(int i=len;i<=n;i++)
            {
                minx=min(minx,s[i-len]);
                ans=max(ans,s[i]-minx);
            }
            if(ans>=0)l=mid;
            else r=mid;
        }
        printf("%d
    ",int(r*1000));
        return 0;
    }

     P28 Codeforces 670C

    离散化,比较熟了。开始题读错了...比较心急,码完这道就肝作业,明天就回学校了..

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1000100
    int n,m,cnt,cot,mx1,mx2,choice;
    int a[N],b[N],z[N],f[N],num[N],tot[N];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)    
        {
            scanf("%d",&a[i]);
            num[i]=a[i];
        }
        cnt=n;
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&z[i]);
            a[++cnt]=z[i];
        }    
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&f[i]);
            a[++cnt]=f[i];
        }
        sort(a+1,a+1+cnt);
        cot=unique(a+1,a+1+cnt)-(a+1);
        for(int i=1;i<=n;i++)
            tot[lower_bound(a+1,a+1+cot,num[i])-a]++;
        choice=1;
        for(int i=1;i<=m;i++)
        {
            int pos1=tot[lower_bound(a+1,a+1+cot,z[i])-a];
            int pos2=tot[lower_bound(a+1,a+1+cot,f[i])-a];
            if(pos1>mx1)
                mx1=pos1,mx2=pos2,choice=i;
            if(pos1==mx1&&pos2>mx2)
                    mx2=pos2,choice=i;
        }
        printf("%d",choice);
        return 0;
    }

     8.31

    逃了开学考躲机房里

    P29 BZOJ3032 

    中位数不知道有什么其他用处,但是这道题的数学推导确实反反复复看了好久

    #include<bits/stdc++.h>
    using namespace std;
    #define N 101000
    #define ll long long
    ll n,m,t,xm,ym,base,ans;
    ll s[N],x[N],y[N]; 
    
    void solve1()
    {
        base=t/n;
        for(ll i=1;i<=t;i++)
            s[x[i]]++;
        for(ll i=1;i<=n;i++)
            s[i]-=base;
        for(ll i=1;i<=n;i++)
            s[i]+=s[i-1];
        sort(s+1,s+1+n);
        for(ll i=1;i<=n;i++)
            ans+=abs(s[i]-s[n+1>>1]);
    }
    
    void solve2()
    {
        memset(s,0,sizeof(s));
        base=t/m;
        for(ll i=1;i<=t;i++)
            s[y[i]]++;
        for(ll i=1;i<=m;i++)
            s[i]-=base;
        for(ll i=1;i<=m;i++)
            s[i]+=s[i-1];
        sort(s+1,s+1+m);
        for(ll i=1;i<=m;i++)
            ans+=abs(s[i]-s[m+1>>1]);
    }
    
    int main()
    {
        scanf("%lld%lld%lld",&n,&m,&t);
        for(ll i=1;i<=t;i++)
            scanf("%d%d",&x[i],&y[i]);
        xm=n>=t?n%t:t%n,ym=m>=t?m%t:t%m;
        if(!xm&&ym)
            printf("row "),solve1();    
        if(xm&&!ym)
            printf("column "),solve2();
        if(!xm&&!ym)
            printf("both "),solve1(),solve2();
        if(xm&&ym)
        {    printf("impossible ");return 0;}
        printf("%lld",ans);
        return 0;
        
    }

     P32 POJ3784

    poj炸了??测不出结果,假装AC

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<queue>
    #include<cstring>
    using namespace std;
    #define N 10100
    int t,p,n,k,mid,cnt;
    int a[N];
    priority_queue<int>bq;
    priority_queue<int,vector<int>,greater<int> >sq;
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&p,&n);
            while(!bq.empty())bq.pop();
            while(!sq.empty())sq.pop();
            memset(a,0,sizeof(a));
            mid=0;cnt=0;
            printf("%d %d
    ",p,n+1>>1);
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                if(a[i]<mid)bq.push(a[i]);
                else sq.push(a[i]);
                if(!(i&1))continue;
                while(bq.size()>i/2)
                    k=bq.top(),bq.pop(),sq.push(k);
                while(sq.size()>i/2+1)
                    k=sq.top(),sq.pop(),bq.push(k);
                mid=sq.top();
                printf("%d ",mid),cnt++;
                if(!(cnt%10))printf("
    ");
            }
            if((n+1>>1)%10)printf("
    ");
        }
        return 0;
    }

     P33 POJ2299

    又是树状数组+离散化的逆序对

    #include<bits/stdc++.h>
    using namespace std;
    #define N 500050
    #define ll long long 
    ll n,m,ans;
    ll a[N],b[N],t[N];
    inline ll lowbit(ll x)
    {    return x&(-x);    }
    inline void add(ll x)
    {
        for(;x<=n;x+=lowbit(x))
            t[x]++;
    }
    inline ll query(ll x)
    {
        ll ret=0;
        for(;x;x-=lowbit(x))
            ret+=t[x];
        return ret;
    }
    inline void init()
    {
        ans=0;
        memset(a,0,sizeof(a));
        memset(t,0,sizeof(t));
        memset(b,0,sizeof(b));
    }
    int main()
    {
        while(scanf("%lld",&n)&&n!=0)
        {
            init();
            for(ll i=1;i<=n;i++)
                scanf("%lld",&a[i]),b[i]=a[i];
            sort(a+1,a+1+n);
            m=unique(a+1,a+1+n)-(a+1);
            for(ll i=1;i<=n;i++)
                b[i]=lower_bound(a+1,a+1+m,b[i])-a;
            for(ll i=n;i;i--)
                ans+=query(b[i]-1),add(b[i]);
            printf("%lld
    ",ans);    
        }
        return 0;
    }

     9.4

    开学了,看了图论的前两节,感觉真的没什么时间写例题了

    P34 POJ2893

    poj又炸了??

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    #define N 1010
    int a[N*N],t[N*N];
    int n,m,k,d,cnt,ans;
    inline int lowbit(int x)
    {
        return x&(-x);
    }
    
    inline int add(int x)
    {
        for(;x<=n;x+=lowbit(x))
            t[x]++;
    }
    
    inline int query(int x)
    {
        int ret=0;
        for(;x;x-=lowbit(x))
            ret+=t[x];
        return ret;
    }
    
    int cal()
    {
        int ans=0;
        for(int i=n*m-1;i;i--)
        {
            ans+=query(a[i]-1);
            add(a[i]);
        }
        return ans;
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&m)&&n)
        {
            memset(t,0,sizeof(t));
            memset(a,0,sizeof(a));
            cnt=0;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    scanf("%d",&k);
                    if(!k)
                        d=m-i;
                    else
                        a[++cnt]=k;
                }    
            ans=cal();
            if(n&1)d=2;
            d%2==ans%2?printf("YES
    "):printf("NO
    ");
        }
        return 0;
    } 

     留了倍增的坑,奇怪的OJ懒得注册了

    P37 st表模板

    void work()
    {
        for(int i=1;i<=n;i++)f[i][0]=a[i];
        int k=log(n)/log(2)+1;
        for(int j=1;j<k;j++)
            for(int i=1;i<=n-(1<<j);i++)
                f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1];
    }
    
    int query()
    {
        int k=log(r-l+1)/log(2);
        return max(f[l][k],f[r-(1<<k)+1][k]);
    }

     P38 POJ3614

    又是读错题,WA了半天,还以为防晒霜给出的两个数也是说范围。。。

    前几次测试在贪心上吃了大亏,现在稍微对比较简单的算法也提高了警惕性。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 3000
    int n,l,ans;
    struct email
    {
        int maxx,minx;
    }a[N];
    struct quq
    {
        int k,num,id;
    } now,use[N];
    bool cmp(email a,email b)
    {
        return a.minx>b.minx;
    }
    bool cmp2(quq a,quq b)
    {
        return a.k>b.k;
    }
    int main()
    {
        scanf("%d%d",&n,&l);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].minx,&a[i].maxx);
        for(int i=1;i<=l;i++)
        {
            scanf("%d%d",&use[i].k,&use[i].num);
            use[i].id=i; 
        }    
        sort(a+1,a+1+n,cmp);
        sort(use+1,use+1+l,cmp2);
        for(int j=1;j<=n;j++)
        {
            now.k=0;
            for(int i=1;i<=l;i++)
            {
                if(use[i].k>=a[j].minx&&use[i].k<=a[j].maxx)
                    if(use[i].num)
                    {
                        now=use[i],use[i].num--;
                        break;
                    }        
            }
            if(now.k)ans++;
        }
        printf("%d
    ",ans);
        return 0;
    }

     P39 POJ3190

    POJ炸了就在BSOJ上交,没注意到没有SPJ,炸到飞起,后来并想不通为什么,交了标程,也只有10分

    才发现没有SPJ。。

    虽然被水题卡半天略气,但是学到了结构体的优先队列

    #include<bits/stdc++.h>
    using namespace std;
    #define N 50500
    int n,cnt,jl[N];
    struct email
    {
        int st,ed,id;
    }a[N];
    bool operator <(const email &a,const email &b)
    {
        if(a.ed==b.ed)
            return a.st>b.st;
        return a.ed>b.ed;
    }
    priority_queue<email>q;
    bool cmp(email a,email b)
    {
        if(a.st==b.st)
            return a.ed<b.ed;
        return a.st<b.st;
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].st,&a[i].ed),a[i].id=i;
        sort(a+1,a+1+n,cmp);
        jl[a[1].id]=++cnt;q.push(a[1]);
        for(int i=2;i<=n;i++)
        {
            email tp=q.top();
            int mx=tp.ed,ans=jl[tp.id];
            if(mx<a[i].st)
                jl[a[i].id]=ans,q.pop();
            else
                jl[a[i].id]=++cnt;    
            q.push(a[i]);        
        }
        printf("%d
    ",cnt);
        for(int i=1;i<=n;i++)
            printf("%d
    ",jl[i]);
        return 0;
    }

     9.5

    今天晚上七点就写完了作业??但是也只写了两道题

    先研究了一下高精,再做了一道很独特的均分权值。第一章例题基本完结,然而poj还是down

    P40 NOIP2012 国王游戏

    P41 Color a Tree

    感觉越来越慌了...水过去了一年现在终于遭报应了...

    9.6

    P44 t2

    9.10 

    占卜DIY

    学习分形,细节好多啊

    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<iostream>
    using namespace std;
    #define N 1010
    int n;
    char a[N][N];
    int power(int x)
    {
        int ret=1;
        for(int i=1;i<=x;i++)
            ret*=3;
        return ret;
    } 
     
    void dfs(int d,int x,int y)
    {
        if(d==1)
        {a[x][y]='X';return;} 
        int s=power(d-2);
        dfs(d-1,x,y);
        dfs(d-1,x,y+2*s);
        dfs(d-1,x+s,y+s);
        dfs(d-1,x+2*s,y);
        dfs(d-1,x+2*s,y+2*s);
    } 
     
    int main()
    {
        while(scanf("%d",&n))
        {
            if(n==-1)break;
            memset(a,' ',sizeof(a));//初始化为空格 
            dfs(n,1,1);
            int s=power(n-1);//3^(n-1)行 3^(n-1)列 
            for(int i=1;i<=s;i++)
                a[i][s+1]=''; //强制结束 无多余空格 
            for(int i=1;i<=s;i++)
                printf("%s
    ",a[i]+1);//往前挪一位 
            printf("-
    ");
        }
        return 0;
    }

     9.11

    今天心态稍微好一点儿了,终于半懵半懂的理解了最近点对

    感觉自己好喜欢看题解啊,导致思维上升缓慢,然而在短时间内里理解一道题的能力以及啃看不懂的东西的能力疯狂增加

    虽然并没有什么用。。。但是讲真,最近点对这种拿给我自己想怎么想得出来...

    POJ3714 Raid

    9.15

    前两天其实已经写了,今天才有空把题解捣鼓出来

    糖果传递

    第一章还有一点儿题没做,但是时间是真的来不及了啊,所以第一章的学习暂时完结吧!!

    完结

    “Make my parents proud,and impress the girl I like.”
  • 相关阅读:
    jQuery插件之artDialog
    jQuery插件之ajaxFileUpload
    jQuery插件之Cookie
    jQuery插件之Form
    jQuery与DOM对象的转换
    jQuery之AJAX
    jQuery之元素筛选
    jQuery之位置
    POJ2096 概率dp 入门
    Sichuan State Programming Contest 2012 C。Counting Pair
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9543109.html
Copyright © 2020-2023  润新知