• 内网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

    待更新。

  • 相关阅读:
    需求变更的种类及应对方式
    SQL Server中连接远程表、查询其它服务器的数据、导入或导出到其它Sql Server服务器数据
    在IE9中MSWC.BrowserType组件无法识别Cookie的问题
    优秀软件的几个重要标准
    对待代码的态度反应着对待自己的态度
    应对企业不断变化的系统
    在SQL中插入®特殊字符
    如何让领导认识到测试的重要性,在沟通时要注意的几点
    男人要补肾,强肾健脑对能持久做程序
    你可能不知道的Visual Studio 2010使用技巧(VS2010的秘密)
  • 原文地址:https://www.cnblogs.com/iamCYY/p/4908888.html
Copyright © 2020-2023  润新知