• 第二周 7.26-8.1


    7.26

    多校第一场1006的一篇题解看了好几天了。

    复习了LCA。只会离线的。

    想了很久其中的状态转移。

    以及dfs序和求和的方法。

    从昨天下午开始码。今天终于码(抄)好了。

    一会补在多校那篇里。

    先补个BC。

    HDU 5312 Sequence

    按照官方题解。

    先看能不能一个。我lower_bound找的。

    然后拆两个的时候不能太暴力。会T的。

    从两边线性找是可以过的。(然而时间也蛮多。

    3-8的情况方便了。

    感觉时间主要在2上。目前也不会更快的方法。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <algorithm>
     4 using namespace std;
     5 int a[20000];
     6 
     7 int main(void)
     8 {
     9     int n;
    10     for(int i=0;;i++)
    11     {
    12         a[i]=3*i*(i-1)+1;
    13         if(a[i]>1000000000) {n=i;break;}
    14     }
    15     int T; cin>>T;
    16     while(T--)
    17     {
    18         int m; scanf("%d",&m);
    19         int x=lower_bound(a,a+n,m)-a;
    20         if(a[x]==m) {printf("1
    "); continue;}
    21         int ans=-1,s=1,t=n-1;
    22         while(s<=t)
    23         {
    24             if(a[s]+a[t]==m) {ans=2;break;}
    25             if(a[s]+a[t]>m) t--;
    26             if(a[s]+a[t]<m) s++;
    27         }
    28         if(ans>0) {printf("%d
    ",ans); continue;}
    29         for(int i=3;i<10;i++)if((m-i)%6==0){ans=i;break;}
    30         printf("%d
    ",ans);
    31     }
    32     return 0;
    33 }
    Aguin

    学最大流的EK算法。

    7.27

    HDU 1532 Drainage Ditches

    最大流模板题。EK过。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 # include <queue>
     6 using namespace std;
     7 # define maxn 210
     8 int N,M,map[maxn][maxn],pre[maxn],flow[maxn];
     9 
    10 int BFS(void)
    11 {
    12     memset(pre,0,sizeof(pre));
    13     queue<int> q; q.push(1);
    14     flow[1]=2147483647;
    15     while(!q.empty())
    16     {
    17         int tem=q.front(); q.pop();
    18         if(tem==M) break;
    19         for(int i=2;i<=M;i++)
    20         {
    21             if(!pre[i]&&map[tem][i]>0)
    22             {
    23                 flow[i]=min(flow[tem],map[tem][i]);
    24                 q.push(i); pre[i]=tem;
    25             }
    26         }
    27     }
    28     if(!pre[M]) return 0;
    29     return flow[M];
    30 }
    31 
    32 int max_flow(void)
    33 {
    34     int ret=0,f;
    35     while(f=BFS())
    36     {
    37         ret+=f;
    38         int pos=M;
    39         while(pos!=1)
    40         {
    41             int tem=pre[pos];
    42             map[tem][pos]-=f;
    43             map[pos][tem]+=f;
    44             pos=tem;
    45         }
    46     }
    47     return ret;
    48 }
    49 
    50 int main(void)
    51 {
    52     while((scanf("%d%d",&N,&M))!=EOF)
    53     {
    54         memset(map,0,sizeof(map));
    55         for(int i=1;i<=N;i++)
    56         {
    57             int S,E,C; scanf("%d%d%d",&S,&E,&C);
    58             map[S][E]+=C;
    59         }
    60         printf("%d
    ",max_flow());
    61     }
    62     return 0;
    63 }
    Aguin

    在补多校1的1007。EK是T的。

    于是顺便看了下SAP。

    感觉相当于在EK的BFS里加了距离标记。保证找到的是最短路径。

    再加上了一个gap的优化。

    神奇的是初始化的时候可以把距离标记置零。过程中会自动调整。

    贴个板子。

     1 int pre[maxn],level[maxn],gap[maxn];
     2 int SAP(int s,int t,int N)//源点s 汇点t 点数N 
     3 {
     4     memset(pre,0,sizeof(pre));//pre记录增广路的前向弧
     5     memset(pre,0,sizeof(level));//level距离标记
     6     memset(pre,0,sizeof(gap)); //gap[i]为距离标记为i的点数 
     7     gap[0]=N; pre[s]=s;//初始化所有点的标记都是0 
     8     int pos=s,flow=0,aug;
     9     while(level[s]<N)//level[s]=N时无法增广 
    10     {
    11         int to;
    12         for(to=1;to<=N;to++) 
    13             if(map[pos][to]>0&&level[to]==level[pos]+1)//寻找可行路 
    14                 break;
    15         if(to<=N) 
    16         {
    17             pre[to]=pos; pos=to;
    18             if(pos==t)//找到s到t的可行路 更新残网 
    19             {
    20                 aug=INF;
    21                 for(int i=pos;i!=s;i=pre[i]) aug=min(aug,map[pre[i]][i]);
    22                 flow+=aug;
    23                 for(int i=pos;i!=s;i=pre[i])
    24                 {
    25                     map[pre[i]][i]-=aug;
    26                     map[i][pre[i]]+=aug;
    27                 }
    28                 pos=s;//重新从s开始寻找可行路 
    29             }
    30         }
    31         else//找不到可行路 更新距离标记 
    32         {
    33             int minlevel=N;
    34             for(int i=1;i<=N;i++)
    35                 if(map[pos][i]>0)
    36                     minlevel=min(minlevel,level[i]);
    37             gap[level[pos]]--;
    38             if(!gap[level][pos]) break;//出现断层 无可行路 
    39             level[u]=minlevel+1;
    40             gap[level[u]]++;
    41             pos=pre[pos];
    42         }        
    43     }
    44     return flow;
    45 }
    Aguin

    7.28

     上午补多校1的1009。

    要在线的LCA。于是学了一下倍增法。

    Link:http://www.cnblogs.com/OUSUO/p/3805715.html

    下午多校。这次终于有能交的题了。

    但是感觉做的效果并不好。签完三题就在浪费时间。

    最后开1010没码完。赛后看题解发现一个地方想错。

    补题吧。

    7.29

    补多校。

    一个线段树敲不对。

    搬迁。

    7.30

    补多校3 1001/1008。

    多校弃疗。

    一直到晚上还没敲出1009。

    后来问了别人思路。

    7.31

    补多校4 1009/1010/1012。

    这场就补三个其他放着先。

    明天开始刷专题。

    今天不小心发现memset并不像想象的那么快。

    T大时真的要看清是不是必须清空阿。

    8.1

    做背包已是一个月前。忘光了。重新从0-1开始。

    HDU 2602 Bone Collector

    滚动数组适用于某一维度的状态只依赖于上一状态的情况。可以把空间降一维。

    需要注意的是更新的时候要注意顺序。否则容易出现把依赖的状态先更新的情况。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 using namespace std;
     6 int dp[1010],v[1010],w[1010];
     7 
     8 int main(void)
     9 {
    10     int T; cin>>T;
    11     while(T--)
    12     {
    13         int N,V; scanf("%d%d",&N,&V);
    14         for(int i=1;i<=N;i++) scanf("%d",v+i);
    15         for(int i=1;i<=N;i++) scanf("%d",w+i);
    16         memset(dp,0,sizeof(dp));
    17         for(int i=1;i<=N;i++)
    18             for(int j=V;j>=w[i];j--)
    19                 dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    20         printf("%d
    ",dp[V]);
    21     }
    22     return 0;
    23 }
    Aguin

    背包问题里面有一类能不能达到的问题。(就是只有背包装满才是可行解)

    以一般的求价值最大的背包为例。

    初始化的时候把dp[0]置0。其他均为负无穷。

    这样一来从dp[0]推出的dp值是正常的。代表可行解。

    从其他dp推出的值无论怎样都是负数。表示无法达到装满的状态。

    HDU 1114 Piggy-Bank

    之前看过挺多完全背包的文章。

    每个都会先从0-1背包过渡到完全背包。

    先用0-1背包的方法逐步优化。最后引出一种O(VN)的方法。

    我觉得在理解滚动数组的基础上这种方法不难理解。

    直接写这种方法了。

    题中要用到上面说到的装满背包的处理方法。

    有一点不同在于问题中要求解的是最小值。

    所以初始化除dp[0]外应为正无穷。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <algorithm>
     4 using namespace std;
     5 # define maxn 505
     6 # define maxV 10010
     7 # define INF 1000000000
     8 int p[maxn],w[maxn],dp[maxV];
     9 
    10 int main(void)
    11 {
    12     int T; cin>>T;
    13     while(T--)
    14     {
    15         int E,F,N;
    16         scanf("%d%d%d",&E,&F,&N);
    17         int V=F-E;
    18         for(int i=1;i<=N;i++) scanf("%d%d",p+i,w+i);
    19         dp[0]=0;
    20         for(int i=1;i<=V;i++) dp[i]=INF;
    21         for(int i=1;i<=N;i++)
    22             for(int j=w[i];j<=V;j++)
    23                 dp[j]=min(dp[j],dp[j-w[i]]+p[i]);
    24         if(dp[V]<INF) printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[V]);
    25         else printf("This is impossible.
    ");
    26     }
    27     return 0;
    28 }
    Aguin

    HDU 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活 (用这么沉重的话题出题真的好吗)

    多重背包就是用二分的方法把每种物品拆分。

    然后转化成0-1背包问题。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 using namespace std;
     6 int v[1000],w[1000],dp[101];
     7 
     8 int main(void)
     9 {
    10     int T; cin>>T;
    11     while(T--)
    12     {
    13         int n,m;
    14         scanf("%d%d",&n,&m);
    15         int cnt=0;
    16         for(int i=1;i<=m;i++)
    17         {
    18             int p,h,c;
    19             scanf("%d%d%d",&p,&h,&c);
    20             int t=1;
    21             while(c>=t)
    22             {
    23                 w[++cnt]=t*p;
    24                 v[cnt]=t*h;
    25                 c-=t;
    26                 t*=2;
    27             }
    28             if(c)
    29             {
    30                 w[++cnt]=c*p;
    31                 v[cnt]=c*h;
    32             }
    33         }
    34         memset(dp,0,sizeof(dp));
    35         for(int i=1;i<=cnt;i++)
    36             for(int j=n;j>=w[i];j--)
    37                 dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
    38         printf("%d
    ",dp[n]);
    39     }
    40     return 0;
    41 }
    Aguin

    对于混合背包问题。

    如果只有0-1背包和完全背包混。

    这两个的写法只有循环最内层增减相反的差别。

    如果加上多重背包。则把多重化为0-1。

    然后就和上面一样了。

    暂时没有找到题目。不过情况不复杂。

    HDU 2159 FATE

    当费用约束为二维的时候。再给dp加上一维即可。

    依旧还是什么背包按什么背包写。

    这个题的增加约束是物品数目。

    所以看成0-1背包或者完全背包都是可以的。

    但是觉得这个题目这样做不好。因为到最后还要搜一遍最小的花费。

    纯当练手。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 using namespace std;
     6 int dp[110][110],a[110],b[110];
     7 
     8 int main(void)
     9 {
    10     int n,m,k,s;
    11     while((scanf("%d%d%d%d",&n,&m,&k,&s))!=EOF)
    12     {
    13         for(int i=1;i<=k;i++) scanf("%d%d",a+i,b+i);
    14         memset(dp,0,sizeof(dp));
    15         for(int i=1;i<=k;i++)
    16             for(int j=1;j<=s;j++)
    17                 for(int l=m;l>=b[i];l--)
    18                     dp[j][l]=max(dp[j][l],dp[j-1][l-b[i]]+a[i]);
    19         if(dp[s][m]<n) {printf("-1
    ");continue;}
    20         int ans=m;
    21         for(int i=0;i<=s;i++)
    22             for(int j=0;j<=m;j++)
    23                 if(dp[i][j]>=n)
    24                     ans=min(ans,j);
    25         printf("%d
    ",m-ans);
    26     }
    27     return 0;
    28 }
    Aguin

    HDU 1712 ACboy needs your help

    分组背包。 每组最多取一个。

    按组递推。每组有不取或者取一个两种选择。

    这样思考的话其实是0-1背包的方法。

    所以滚动数组的时候容量要递减着推。

    【下午题目看错真是坑死。】

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 using namespace std;
     6 int map[110][110],dp[110];
     7 
     8 int main(void)
     9 {
    10     int n,m;
    11     while((scanf("%d%d",&n,&m))!=EOF)
    12     {
    13         if(!n&&!m) break;
    14         for(int i=1;i<=n;i++)
    15             for(int j=1;j<=m;j++)
    16                 scanf("%d",&map[i][j]);
    17         memset(dp,0,sizeof(dp));
    18         for(int i=1;i<=n;i++)
    19             for(int j=m;j>=0;j--)
    20                 for(int k=1;k<=j;k++)
    21                     dp[j]=max(dp[j],dp[j-k]+map[i][k]);
    22         printf("%d
    ",dp[m]);
    23     }
    24     return 0;
    25 }
    Aguin

    晚上打了个BC。

    第一题水果。

    第二题抄了个板子。时间快到了才码完。然而WA。

    HDU 5339 Untitled

    总共二十个数。暴搜差不多是1e6情况。1s勉强。

    但是很容易想到不会取大于被除数的c。

    这里就能剪掉很多。

    应该还可以加其他优化。例如去重。或者存在一个数是另一个数的因子之类。

    用的BFS。找到的第一个就是ans。0ms。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <queue>
     4 # include <algorithm>
     5 using namespace std;
     6 typedef pair<int,int> pii;
     7 
     8 int main(void)
     9 {
    10     int T; cin>>T;
    11     while(T--)
    12     {
    13         int n,a,num[21],ok=0;
    14         scanf("%d%d",&n,&a);
    15         for(int i=0;i<n;i++) scanf("%d",num+i);
    16         sort(num,num+n);
    17         queue<pii> q;
    18         q.push(pii(a,0));
    19         while(!q.empty())
    20         {
    21             pii tem=q.front(); q.pop();
    22             int x=tem.first,t=tem.second;
    23             for(int i=n-1;i>=0;i--)
    24             {
    25                 if(num[i]<=x)
    26                 {
    27                     int y=x%num[i];
    28                     if(y==0)
    29                     {
    30                         ok=1;
    31                         printf("%d
    ",t+1);
    32                         while(!q.empty()) q.pop();
    33                         break;
    34                     }
    35                     else q.push(pii(y,t+1));
    36                 }
    37             }
    38         }
    39         if(!ok) printf("-1
    ");
    40     }
    41     return 0;
    42 }
    Aguin

    待补。

  • 相关阅读:
    实现将Web页面的内容,Export To Excel的功能
    设计模式点滴
    Vista上运行VisualStudio2005,调试asp.net程序的怪问题
    《天风文章》V1.0.0使用说明
    呵呵,cnblog排名进4000了,留念一下!
    一个程序只能启动一次实现
    VS中"生成注释WEB页"的问题
    用友Cell组件使用总结
    《天风文章》 V1.1.0设计文档
    SQL 数据库的自动备份(Procedures实现)
  • 原文地址:https://www.cnblogs.com/Aguin/p/4677456.html
Copyright © 2020-2023  润新知