zoukankan      html  css  js  c++  java
  • 内网OJ题解

    OJ1001A+B Problem:

      a+b。

    #include<bits/stdc++.h>
    using namespace std;
    int main(){
        int a,b;
        cin>>a>>b;
        cout<<a+b<<endl;
        return 0;
    }
    my code

    OJ1002阶乘之和

      c表示n!因子5的次数,则c=[n/5]+[n/25]+[n/125]+...  
      末尾0的个数=min(因子2的次数,因子5的次数)=c。
      原问题即为n!/(10^c) = x (mod 10)
      等价为两个方程:
        n!/(10^c) = x (mod 2)
        n!/(10^c) = x (mod 5)
      分类讨论,
        当n<=1时,答案为0 1
        当n>1时,第一个方程的解可以是所有偶数,转化为x = 0(mod 2)。
        考虑第二个方程,
          n!/(10^c)=x (mod 5)
        设h(n)=小于等于n且与5互质的数的乘积:
        可以分组,因为1*2*3*4 = 6*7*8*9 ...(mod 5)
        所以h(n) = (4!)^(n/5)*(n%5)! (mod 5)。
             = (-1)^(n/5)*(n%5)! (mod 5)。
        n!/(10^c)=h(n)*h(n/5)*...*[(2^c)^-1] = x (mod 5)。
        -->(-1)^c*(n%5)!*(n/5%5)!*(n/25%5)!...*(3^c)= x (mod 5)
        -->(-1)^c*(3^(c%4))*(n%5)!*(n/5%5)!*(n/125%5)!... = x(mod 5)。
         2,5互质,用CRT合并两个方程组

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    typedef long long int64;
    int64 n,c;
    int64 fac(int64 x){int64 res=1;for (int i=1;i<=x;++i) res*=i;return res;}
    /*
        c表示n!因子5的次数,则c=[n/5]+[n/25]+[n/125]+... 
        末尾0的个数=min(因子2的次数,因子5的次数)=c。 
        原问题即为n!/(10^c) = x (mod 10)
        等价为两个方程:
            n!/(10^c) = x (mod 2)
            n!/(10^c) = x (mod 5)
        分类讨论,
            当n<=1时,答案为0 1
             当n>1时,第一个方程的解可以是所有偶数,转化为x = 0(mod 2)。
             考虑第二个方程,
                 n!/(10^c)=x (mod 5)
            设h(n)=小于等于n且与5互质的数的乘积:
                可以分组,因为1*2*3*4 = 6*7*8*9 ...(mod 5)
                所以h(n) = (4!)^(n/5)*(n%5)! (mod 5)。
                        = (-1)^(n/5)*(n%5)! (mod 5)。
            n!/(10^c)=h(n)*h(n/5)*...*[(2^c)^-1] = x (mod 5)。
            -->(-1)^c*(n%5)!*(n/5%5)!*(n/25%5)!...*(3^c)= x (mod 5)
            -->(-1)^c*(3^(c%4))*(n%5)!*(n/5%5)!*(n/125%5)!... = x(mod 5)。 
        2,5互质,用CRT合并两个方程组  
    */
    int main(){
        cin>>n;
        if (n==0||n==1){cout<<0<<endl<<1<<endl;return 0;}
        int64 t=1;
        for (int i=1;n;n/=5,++i){c+=n/5;t=t*fac(n%5)%5;}
        if (c&1) t=-t;
        for (int i=1;i<=c%4;++i) t=t*3%5;
        t=(t+5)%5;
        cout<<c<<endl<<t*6%10<<endl;
        return 0;
    }
    my code

    OJ1003是男人下100层

      f[i][0],f[i][1]分别代表从底部走到第i块板子左端和右端的最小距离,用线段树单点查询被端点被哪个区间覆盖即可更新答案。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=100015;
    int n,k;
    struct Tdata{
        int h,l,r;
        void init(){scanf("%d%d%d",&h,&l,&r);}
        bool operator <(const Tdata &b)const{return h>b.h;}
    }data[maxn];
    struct Tsegment{
        int cov[maxn<<2];
        void clear(int p){
            if (cov[p]){
                cov[p<<1]=cov[p<<1|1]=cov[p];
                cov[p]=0;
            }
        }
        void modify(int p,int l,int r,int a,int b,int v){
            if (l==a&&r==b){cov[p]=v;return;}
            clear(p);int mid=(l+r)>>1;
            if (b<=mid) modify(p<<1,l,mid,a,b,v);
            else if (a>=mid+1) modify(p<<1|1,mid+1,r,a,b,v);
            else{modify(p<<1,l,mid,a,mid,v);modify(p<<1|1,mid+1,r,mid+1,b,v);}
        }
        int query(int p,int l,int r,int x){
            if (cov[p]) return cov[p];
            int mid=(l+r)>>1;
            if (x<=mid) return query(p<<1,l,mid,x);
            else return query(p<<1|1,mid+1,r,x);
        }
        void modify(int l,int r,int v){modify(1,1,1000,l,r,v);}
        int query(int x){return query(1,1,1000,x);}
    }seg;
    void init(){
        scanf("%d%d",&n,&k);
        for (int i=1;i<=n;++i) data[i].init();
        sort(data+1,data+n+1);
    //    for (int i=1;i<=n;++i) cout<<data[i].h<<' '<<data[i].l<<' '<<data[i].r<<endl;
    }
    int f[maxn][2];
    void work(){
        memset(f,63,sizeof(f));
        seg.modify(data[1].l,data[1].r,1);
        for (int j,i=2;i<=n;i=j){
            for (j=i;j<=n&&data[j].h==data[i].h;++j){
                int idx1=seg.query(data[j].l),idx2=seg.query(data[j].r);
    //            cout<<"fuckpp"<<j<<' '<<idx1<<' '<<idx2<<endl;
                if (data[idx1].h-data[j].h<=k){
                    if (idx1==1) f[j][0]=data[1].h-data[j].h;
                    else f[j][0]=min(f[idx1][0]+data[j].l-data[idx1].l+data[idx1].h-data[j].h,
                                    f[idx1][1]+data[idx1].r-data[j].l+data[idx1].h-data[j].h);
                }
                if (data[idx2].h-data[j].h<=k){
                    if (idx2==1) f[j][1]=data[1].h-data[j].h;
                    else f[j][1]=min(f[idx2][1]+data[idx2].r-data[j].r+data[idx2].h-data[j].h,
                                    f[idx2][0]+data[j].r-data[idx2].l+data[idx2].h-data[j].h);
                }
            }
            for (int k=i;k<=j-1;++k) seg.modify(data[k].l,data[k].r,k);
        }
        printf("%d
    ",min(f[n][0],f[n][1]));
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code

    OJ1004讲笑话

      用sum[i]记录前缀和为i的位置数量。

      ans=sum[0]+Σsum[i]*(sum[i]-1)/2。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int n,sum[2000015];
    int main(){
        scanf("%d",&n);int cur=n;
        for (int x,i=1;i<=n;++i){
            scanf("%d",&x);
            ++sum[cur+=x];
        }
        int res=sum[n];
        for (int i=0;i<=2000000;++i) res=(res+1ll*sum[i]*(sum[i]-1)/2)%999999;
        cout<<res<<endl;
        return 0;
    }
    my code

    OJ1006海岛之桥

      最小生成树。

    var
      ans,i,j,n:longint;
      dis:array[1..100,1..100]of longint;
      bo:array[1..100]of boolean;
    procedure mst;
    var
      min,mini:longint;
      lowest:array[1..100]of longint;
    begin
      for i:=2 to n do
        lowest[i]:=maxlongint;
      lowest[1]:=0;
      while true do
      begin
        min:=maxlongint;
        for i:=1 to n do
        begin
          if (bo[i]) and (lowest[i]<min) then
          begin
            min:=lowest[i];
            mini:=i;
          end;
        end;
        if min=maxlongint then
          break;
        bo[mini]:=false;
        ans:=ans+min;
        for i:=1 to n do
          if (bo[i]) and (dis[mini,i]<lowest[i]) then
            lowest[i]:=dis[mini,i];
      end;
    end;
    
    begin
      readln(n);
      for i:=1 to n-1 do
        for j:=i+1 to n do
        begin
          read(dis[i,j]);
          dis[j,i]:=dis[i,j];
        end;
      fillchar(bo,sizeof(bo),true);
      mst;
      writeln(ans);
    end.
    my code

    OJ1007[jsoi2008]星球大战

      离线处理,利用并查集求连通块数,将删点变为加点。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=1000010;
    int n,m,k,res,tot,v[maxn],in[maxn],fa[maxn],ans[maxn],now[maxn],pre[maxn],son[maxn],des[maxn];
    void Connect(int a,int b){
        pre[++tot]=now[a];
        now[a]=tot;
        son[tot]=b;
    }
    void Init(){
        scanf("%d%d",&n,&m);
        for (int x,y,i=1;i<=m;++i){
            scanf("%d%d",&x,&y);
            Connect(x,y),Connect(y,x);
        }
        scanf("%d",&k);
        for (int i=1;i<=k;++i){
            scanf("%d",&des[i]);
            v[des[i]]=1;
        }
    }
    int Get(int x){return fa[x]=fa[x]==x?x:Get(fa[x]);}
    void Put(int x){
        ++res;
        for (int p=now[x];p;p=pre[p]){
            int y=son[p];
            if (!in[y]) continue;
            int w=Get(y);
            if (x!=w) fa[w]=x,--res;
        }
        in[x]=1;
    }
    void Work(){
        for (int i=0;i<n;++i) fa[i]=i;
        for (int i=0;i<n;++i) if (!v[i]) Put(i);
        ans[k+1]=res;
        for (int i=k;i>=1;--i) Put(des[i]),ans[i]=res;
        for (int i=1;i<=k+1;++i) printf("%d
    ",ans[i]);
    }
    int main(){
        Init();
        Work();
        return 0;
    }
    my code

    OJ1009剑圣的逃跑

      f[i][j][k]代表当前在(i,j)已使用k次疾风步的最小伤害。

    var
      i,ci,j,k,m,n,q,minn,t:longint;
      a:array[0..202,0..404]of longint;
      f:array[0..202,0..404,0..202]of integer;
    
    function min(a,b:longint):longint;
    begin
      if a>=b then min:=b
      else min:=a;
    end;
    
    begin
      readln(n,q);
      readln(m);
      for i:=1 to n do
        begin
          for j:=1 to i*2-1 do
            read(a[i,j]);
          readln;
        end;
      fillchar(f,sizeof(f),$7f);
      f[1,1,1]:=0;
      f[1,1,0]:=a[1,1];
      for i:=1 to n-1 do
        for j:=1 to i*2-1 do
          for k:=0 to q do
            for t:=0 to 2 do
              f[i+1,j+t,k]:=min(min(f[i+1,j+t,k],f[i,j,k-1]),f[i,j,k]+a[i+1,j+t]);
      minn:=maxlongint;
      for i:=1 to n*2-1 do
        if f[n,i,q]<minn then
            minn:=f[n,i,q];
      if minn>=m then
         writeln('DEAD')
      else
         writeln(m-minn);
    end.
    my code

    OJ1011选数

      差分约束系统。可以参照:http://ycool.com/post/m2uybbf

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    /*
        令sum[i]代表i及之前选了多少个点
        对于条件(a,b,c),即可化为
            sum[b]-sum[a-1]>=c
        还存在条件
            sum[i]-sum[i-1]>=0
            sum[i]>=0 
        转化为 sum[b]>=c+sum[a-1].
        比较最长路三角不等式,dis[b]>=dis[a-1]+w(a-1,b)。
        于是可以令0点dis=0,并连接0和每个i,边权为0
        对于条件(a,b,c),连边(a-1,b,c)。
        做最长路即可。 
    */
    const int maxn=100015,maxm=500015;
    int n,tot,now[maxn],pre[maxm],son[maxm],val[maxm];
    void connect(int u,int v,int w){pre[++tot]=now[u];now[u]=tot;son[tot]=v;val[tot]=w;}
    void init(){
        scanf("%d",&n);
        for (int u,v,w,i=1;i<=n;++i){
            scanf("%d%d%d",&u,&v,&w);
            ++u;++v;
            connect(u-1,v,w);
        }
        for (int i=1;i<=50001;++i){
            connect(0,i,0);
            connect(i,i+1,0);
            connect(i,i-1,-1); 
        }
    }
    /*
        wa了 好像漏了一个条件
        sum[i]-sum[i-1]<=1
        即sum[i-1]-sum[i]>=-1
        即dis[i-1]>=dis[i]-1
        连接(i,i-1,-1)。 
    */
    bool inq[maxn];
    int head,tail,q[maxn],dis[maxn];
    void spfa(int s){
        memset(dis,200,sizeof(dis));
        dis[s]=0;q[1]=s;head=0;tail=1;inq[s]=1;
        while (head!=tail){
            if (++head==maxn) head=1;
            int u=q[head];
            for (int p=now[u];p;p=pre[p])
                if (dis[son[p]]<dis[u]+val[p]){
                    dis[son[p]]=dis[u]+val[p];
                    if (!inq[son[p]]){
                        if (++tail==maxn) tail=1;
                        q[tail]=son[p];inq[son[p]]=1;
                    }
                }
            inq[u]=0;
        }
    }
    void work(){
        spfa(0);
        printf("%d
    ",dis[50002]);
    }
    int main(){
        freopen("data11.in","r",stdin);
        init();
        work();
        return 0;
    }
    my code

    OJ1012酒鬼

      DP。f[i][j]代表当前做到前i瓶,上一个没喝的瓶在i-j。

      f[i][0]=max(f[i-1][0],f[i-1][1],f[i-1][2])。

      f[i][1]=f[i-1][0]+v[i]。

      f[i][2]=f[i-1][1]+v[i]。

      ans=max(f[n][0],f[n][1],f[n][2])。

    var
        f:array[0..1000,0..2] of longint;
        i,v:longint;
    function max(a,b,c:longint):longint;
    begin
        if a>b then max:=a
        else max:=b;
        if c>max then max:=c;
    end;
    begin
        readln(i);
        for i:=1 to i do
        begin
            readln(v);
            f[i,0]:=max(f[i-1,0],f[i-1,1],f[i-1,2]);
            f[i,1]:=f[i-1,0]+v;
            f[i,2]:=f[i-1,1]+v;
        end;
        writeln(max(f[i,0],f[i,1],f[i,2]));
    end.
    my code

    OJ1014埃及分数

      IDA*:http://blog.csdn.net/u014800748/article/details/47376435。

    #include<cstdio>
    #include<cassert>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxdep=115;
    typedef long long int64;
    /*
        假设第i-1层的分母为x,剩下的分数和为e/f,i的分母为y,则有
            1/x<1/y-->y>x
            1/y*(depth-i+1)>e/f-->y<(depth-i+1)*f/e 
            1/y<e/f->y>f/e
            max(x,f/e)<y<(depth-i+1)*f/e
    */
    bool got;
    int64 fmn=1e18,res[maxdep],seq[maxdep];
    int64 gcd(int64 a,int64 b){return !b?a:gcd(b,a%b);}
    void update(int64 seq[],int64 depth){
        got=1;
        if (seq[depth]<fmn){
            fmn=seq[depth];
            memcpy(res,seq,sizeof(int64)*(depth+1));
        }
    }
    void dfs(int64 cur,int64 x,int64 e,int64 f,int64 depth){
        if (cur==depth){
            if (e!=1) return;
            seq[depth]=f;
            update(seq,depth);
            return;
        }
        int64 l=x+1,r=(depth-cur+1)*f/e-((depth-cur+1)*f%e==0);
        for (int64 i=l;i<=r;++i){
            seq[cur]=i;
            int64 nf=f*i,ne=i*e-f,d=gcd(nf,ne);
            if (ne<=0) continue;
            dfs(cur+1,i,ne/=d,nf/=d,depth);
        }
    }
    int64 a,b;
    int main(){
        scanf("%I64d%I64d",&a,&b);
        int64 d=gcd(a,b),depth;
        for (depth=1,a/=d,b/=d;!got;dfs(1,0,a,b,depth++));
        for (int64 i=1;i<depth-1;++i) printf("%I64d ",res[i]);
        printf("%I64d
    ",res[depth-1]);
    }
    /*
        ‘以下推导错误..’ 
        迭代加深搜索,因为状态过多所以bfs无法保存。
        因为要求最少数量,考虑枚举深度,并利用dfs空间小的特点来搜索。
        假设当前最大深度为depth,第i层的是1/x
            对于之后枚举的1/y,满足1/y<1/x,即y>x 
            还需满足(depth-i)*1/y>a/b-1/x
            可推出(depth-i)*1/y>a/b-1/y,(推导错误)。 
                (depth-i+1)*1/y>a/b 
                1/y>(a/b)/(depth-i+1)。
                y<(depth-i+1)*b/a
        所以x<y<(depth-i+1)*b/a 
    */
    my code

    OJ1015一笔画

      对于无向图,笔画数=Σmax(1,每个连通块内奇点数/2)。

      拓展:对于有向图,笔画数=Σmax(1,每个连通块内入度-出度为1的点数)。注意要满足连通块内入度-出度为1的点数=连通块内出度-入度为1的点数,否则不知道怎么做...

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=1015;
    int n,m,s;
    vector<int> g[maxn];
    void init(){
        scanf("%d%d",&n,&m);
        for (int u,v,i=1;i<=m;++i){
            scanf("%d%d",&u,&v);
            g[u].push_back(v);
            g[v].push_back(u);
        }
    }
    bool vis[maxn];
    void dfs(int u){
        vis[u]=1;if (g[u].size()&1) ++s;
        for (unsigned int i=0;i<g[u].size();++i)
            if (!vis[g[u][i]]) dfs(g[u][i]);
    }
    void work(){
        int res=0;
        for (int i=1;i<=n;++i)
            if (!vis[i]&&g[i].size()){
                s=0;dfs(i);
                res+=max(1,s>>1);
            }
        printf("%d
    ",res);
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code

     OJ1017技能树

      递推。

      f[i][j]代表节点数为i个高度为j的满足条件的二叉树有多少颗
      g[i][j]代表节点数为i个高度<=j的满足条件的二叉树有多少颗
      f[i][j]=sigma(2*f[k][j-1]*g[i-1-k][j-1]-f[k][j-1]*f[i-1-k][j-1])。

    #include<iostream>
    using namespace std;
    const int mod=9901;
    int n,m,f[315][115],g[315][115];
    /*
        f[i][j]代表节点数为i个高度为j的满足条件的二叉树有多少颗
        g[i][j]代表节点数为i个高度<=j的满足条件的二叉树有多少颗
        f[i][j]=sigma(2*f[k][j-1]*g[i-1-k][j-1]-f[k][j-1]*f[i-1-k][j-1])。 
    */
    int main(){
        cin>>n>>m;
        f[1][1]=g[1][1]=1;
        for (int j=2;j<=m;++j)
            for (int i=1;i<=n;++i){
                for (int k=1;k<=i-1;++k)
                    f[i][j]=(1ll*f[i][j]+2ll*f[k][j-1]*g[i-1-k][j-1]%mod-1ll*f[k][j-1]*f[i-1-k][j-1]%mod+mod)%mod;
                g[i][j]=(g[i][j-1]+f[i][j])%mod;
            }
        cout<<f[n][m]<<endl;
        return 0;
    }
    my code

    OJ1019观光游览

      DP。

      f[i][j]代表前i个格子安排j个人(最后一个人管到i)所能得到的最大权值

      f[i][j]=max(f[k-1][j-1]+w(k,i)).
      现在考虑w(j,i)怎么求,即被[j,i]完全覆盖的景点权值和。
      区间[a,b]被完全覆盖,满足 a>=k且b<=i
      数据范围较小,用二维前缀和即可。 查询sum(k,1,m,i)。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=115;
    /*
        f[i][j]代表前i个格子安排j个人(最后一个人管到i)所能得到的最大权值
        f[i][j]=max(f[k-1][j-1]+w(k,i)).
        现在考虑w(j,i)怎么求,即被[j,i]完全覆盖的景点权值和。
        区间[a,b]被完全覆盖,满足 a>=k且b<=i 
        数据范围较小,用二维前缀和即可。 查询sum(k,1,m,i)。 
    */
    int m,n,k,sum[maxn][maxn],f[maxn][maxn];
    int get_sum(int x1,int y1,int x2,int y2){return sum[x2][y2]+sum[x1-1][y1-1]-sum[x1-1][y2]-sum[x2][y1-1];} 
    void init(){
        scanf("%d%d",&m,&n);
        for (int x,y,v,i=1;i<=n;++i){
            scanf("%d%d%d",&x,&y,&v);
            sum[x][y]+=v;
        }
        scanf("%d",&k);
    }
    void work(){
        for (int i=1;i<=m;++i)
            for (int j=1;j<=m;++j)
                sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
        memset(f,200,sizeof(f));
        f[0][0]=0;
        for (int i=1;i<=m;++i)
            for (int j=1;j<=k;++j)
                for (int l=1;l<=i;++l)
                    f[i][j]=max(f[i][j],f[l-1][j-1]+get_sum(l,1,m,i));
        printf("%d
    ",f[m][k]);
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code

     OJ1021谣言的传播

      floyd。求出全源最短路后枚举起始点更新答案即可。

    var
    min,mini,n,i,j,k,m,max:longint;
    g:array[1..100,1..100]of longint;
    dist:array[1..100,1..100]of longint;
    begin
    readln(n);
    fillchar(g,sizeof(g),$7f);
    for i:=1 to n do
    begin
      read(m);
      for j:=1 to m do
      read(k,g[i,k]);
      readln;
    end;
    for k:=1 to n do
    for i:=1 to n do
    if g[i,k]<>2139062143 then
    for j:=1 to n do
    if g[k,j]<>2139062143 then
    if g[i,j]>g[i,k]+g[k,j] then
    g[i,j]:=g[i,k]+g[k,j];
    min:=maxlongint;
    for i:=1 to n do
      begin
         max:=-2139062143;
         for j:=1 to n do
           if i<>j then
             if g[i,j]>max then
               max:=g[i,j];
         if max<min then
           begin
             min:=max;
             mini:=i;
           end;
      end;
    if min=2139062143 then
    writeln('disjoint')
    else
    writeln(mini,' ',min);
    readln;
    end.
    my code

    OJ1023奖金

      拓扑排序DP。f[i]代表i最小工资。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=10010,maxm=20010;
    int n,m,tot,ind[maxn],f[maxn],now[maxn],pre[maxm],son[maxm];
    void connect(int u,int v){
        pre[++tot]=now[u];
        now[u]=tot;
        son[tot]=v;
        ind[v]++;
    }
    void read(int &x){
        char ch;
        for (ch=getchar();!isdigit(ch);ch=getchar());
        for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    }
    void init(){
        read(n),read(m);
        for (int i=1,u,v;i<=m;++i){
            read(u),read(v);
            connect(v,u);
        }
    }
    int q[maxn];
    bool vis[maxn];
    void top(int st){
        int head=0,tail=1;
        f[st]=100,q[1]=st,vis[st]=1;
        while (head!=tail){
            int u=q[++head];
            for (int p=now[u];p;p=pre[p]){
                f[son[p]]=max(f[u]+1,f[son[p]]);
                if (!--ind[son[p]]) q[++tail]=son[p],vis[son[p]]=1; 
            }
        }
    }
    void work(){
        for (int i=1;i<=n;++i) if (!ind[i]&&!vis[i]) top(i);
        for (int i=1;i<=n;++i) if (!vis[i]){
            puts("Poor Xed");
            return;
        }
        int ans=0;
        for (int i=1;i<=n;++i) ans+=f[i];
        printf("%d
    ",ans);
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code

     OJ1025魔法书

      背包。f[i]代表话费i的时间所能得到的最大获益。显然a[i]小的更划算,所以按降序排序即可背包。

    program q1025;
    var
      f:array[0..1000000] of longint;
      bt:array[0..300] of longint;
      t:array[0..300] of longint;
      bo,v:array[0..300,-1..300] of longint;
      n,i,j,m,p,b,c,k:longint;
    
    procedure swap(var a,b:longint);
    var
      t:longint;
    begin
      t:=a;
      a:=b;
      b:=t;
    end;
    
    procedure qsort(l,r,k: longint);
    var
      i,j,x,y: longint;
    begin
      i:=l;
      j:=r;
      x:=bo[k][(l+r) div 2];
      repeat
        while bo[k,i]<x do
          inc(i);
        while x<bo[k,j] do
          dec(j);
        if not(i>j) then
        begin
          swap(bo[k,i],bo[k,j]);
          inc(i);
          j:=j-1;
        end;
      until i>j;
      if l<j then
        qsort(l,j,k);
      if i<r then
        qsort(i,r,k);
    end;
    
    function max(a,b:longint):longint;
    begin
      if a>b then exit(a);
      exit(b);
    end;
    
    begin
      readln(n,m,p);
      for i:=1 to m do
        read(bo[i][0]);
      readln;
      for i:=1 to n do
      begin
        readln(b,c);
        inc(bo[c][-1]);
        bo[c][bo[c,-1]]:=b;
      end;
      for i:=1 to m do
        qsort(1,bo[i][-1],i);
      for i:=1 to m do
        for j:=1 to bo[i,-1] do
        begin
          bo[i,j]:=bo[i,j]+bo[i,j-1];
          v[i,j]:=v[i,j-1]+1;
        end;
      for i:=1 to n do
        for j:=p downto 0 do
          for k:=1 to bo[i,-1] do
            if j>=bo[i,k] then
              f[j]:=max(f[j],f[j-bo[i,k]]+v[i,k]);
      writeln(f[p]);
    end.
    View Code

     OJ1027[Usaco2008 Jan]无线电通讯塔

      树形DP。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int maxn=50010,maxm=100010,inf=(int)1e8;
    int n,tot,now[maxn],pre[maxm],son[maxm];
    void connect(int u,int v){
        pre[++tot]=now[u];
        now[u]=tot;
        son[tot]=v;
    }
    void read(int &x){
        char ch;
        for (ch=getchar();!isdigit(ch);ch=getchar());
        for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar());
    }
    void init(){
        read(n);
        for (int i=1,u,v;i<=n-1;++i){
            read(u),read(v);
            connect(u,v),connect(v,u);
        }
    }
    int f[maxn][3];
    void dfs(int u,int fa){
        int sum=0;
        f[u][1]=1,f[u][0]=inf;;
        for (int p=now[u];p;p=pre[p]){
            if (son[p]==fa) continue;
            dfs(son[p],u);
            f[u][2]+=f[son[p]][0];
            f[u][1]+=min(f[son[p]][0],min(f[son[p]][1],f[son[p]][2]));
            sum+=min(f[son[p]][0],f[son[p]][1]);
        }
        for (int p=now[u];p;p=pre[p]){
            if (son[p]==fa) continue;
            f[u][0]=min(f[u][0],sum+f[son[p]][1]-min(f[son[p]][0],f[son[p]][1]));
        }
    }
    void work(){
        dfs(1,0);
        printf("%d
    ",min(f[1][0],f[1][1]));
    }
    int main(){
        init();
        work();
        return 0;
    }
    my code

    OJ1034电梯

      背包。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int max(int a,int b){
        if (a>b) return a;
        return b;
    }
    int main(){
        int w,n,ans=0;
        int m[10000],age[10000],f[10000];
        cin>>w>>n;
        for (int i=0;i<n;++i)
            cin>>m[i];
        for (int i=0;i<n;++i){    
            cin>>age[i];
            ans+=age[i];
        }
        memset(f,0,sizeof(f));
        for (int i=0;i<n;++i)
            for (int j=w;j>=m[i];--j)
                f[j]=max(f[j],f[j-m[i]]+age[i]);
        ans-=f[w];
        cout<<ans<<endl;
        //system("pause");
        return 0;
    }
    my code

    OJ1035生日蛋糕

      背包。注意在重量最大的前提下要求出最小蛋糕数。

      f[i].w,f[i][j].n,代表在总重量在模n意义下=i的最大重量,和在此前提下的最少数目。

    var
        n , m , i , j , k : longint;
        a: array[ 1 .. 2000 ] of longint;
        b , bb : array[ 0 .. 10000 ] of boolean;
        f , ff , p , pp: array[ 0 .. 10000 ] of longint;
    
    begin
        readln( n , m );
        for i := 1 to m do
            readln( a[ i ] );
        b[ 0 ] := true;
        for i := 1 to m do
        begin
            for j := n - 1 downto 0 do
                if b[ j ] then
                begin
                    bb[ j ] := true;
                    bb[ ( j + a[ i ] ) mod n ] := true;
                    if ( f[ ( j + a[ i ] ) mod n ] < f[ j ] + a[ i ] ) or
                    ( f[ ( j + a[ i ] ) mod n ] = f[ j ] + a[ i ] ) and
                    ( p[ ( j + a[ i ] ) mod n ] > p[ j ] + 1 ) then
                    begin
                        ff[ ( j + a[ i ] ) mod n ] := f[ j ] + a[ i ];
                        pp[ ( j + a[ i ] ) mod n ] := p[ j ] + 1;
                    end;
                end;
            b := bb;
            f := ff;
            p := pp;
        end;
        if p[ 0 ] > 0 then
            writeln( f[ 0 ] , ' ' , p[ 0 ] )
        else
            writeln( 'no answer' );
    end.
    my code

    待更新。

  • 相关阅读:
    leetcode 33. Search in Rotated Sorted Array
    leetcode 32. Longest Valid Parentheses
    leetcode 28. Implement strStr()
    leetcode 27. Remove Element
    leetcode 26. Remove Duplicates from Sorted Array
    leetcode 24. Swap Nodes in Pairs
    leetcode 22. Generate Parentheses
    树莓派的频率管理和热控制
    sql执行insert插入一条记录同时获取刚插入的id
    全程直播个人博客重构过程,采用springboot+dubbo+jpa技术栈。
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4908888.html
Copyright © 2011-2022 走看看