【转】hdu 3947 River Problem 神之网络流

看到AClist里面有dzy就知道是网络流 最后还是没想出来 只好找题解了Orz

基础知识

本题题解 其中那个y[i]前面应该是负号 作者打错了

 判无解的时候是不满流 要用流量判 不要用费用判!!!!

膜拜此题Orz

#include

using namespace std;

const int maxn=2000 + 10, maxm=maxn*maxn*2;

 

const int maxl=999999999;

inline int Min(int a,int b){return a

inline int Max(int a,int b){return a>b?a:b;}

struct st

{

         int y,d;

         int ne;

         int bro;

         int f;

} e[maxm];

int ee;

int st[maxn];

int n,m;

void addedge(int x,int y,int d,int f)

{//给顶点x和y间添加一条费用d,流量f的边

         e[ee].y=y;e[ee].d=d;e[ee].ne=st[x];e[ee].f=f;st[x]=ee++;

         e[ee].y=x;e[ee].d=-1*d;e[ee].ne=st[y];e[ee].f=0;st[y]=ee++;

         e[ee-2].bro=ee-1;e[ee-1].bro=ee-2;

}

int d[maxn],p[maxn];

//spfa所用到起点的最短距离(这里距离相当于cost)和路径记录之前的一个节点

int c[maxn];//spfa所用数组:是否在队列中

int que[maxn],head,tail;//spfa专用队列

int flow=0;

int spfa(int sx,int ex,int n)//求sx到ex的一次费用增广

{//如果没有增广路就返回maxl否则返回费用

         int i,j,k;

         for (i=0;i

         memset(c,0,sizeof(c));//初始化都没进

         d[sx]=0;

         que[head=0]=sx;tail=1;

         c[sx]=1;

         while (head!=tail)//spfa开始

         {

                   k=que[head++];head%=maxn;

                   c[k]=0;

                   for (i=st[k];i!=-1;i=e[i].ne) if (e[i].f)

                            if (d[k]+e[i].d

                            {

                                     d[e[i].y]=d[k]+e[i].d;

                                     p[e[i].y]=i;

                                     if (c[e[i].y]==0)

                                     {

                                               c[e[i].y]=1;

                                               if (e[i].d<0){head=(head-1+maxn)%maxn;que[head]=e[i].y;}

                                               else

                                               {que[tail++]=e[i].y;tail%=maxn;}

                                     }

                            }

         }

         if (d[ex]==maxl) return maxl;//如果无法到达终点返回maxl

         k=maxl;

         for (i=ex;i!=sx;i=e[e[p[i]].bro].y)       k=Min(k,e[p[i]].f);//计算流

         for (i=ex;i!=sx;i=e[e[p[i]].bro].y)//增加反向边

         {

                   e[p[i]].f-=k;

                   e[e[p[i]].bro].f+=k;

         }

         flow+=k;

         return d[ex]*k;//返回费用为流大小*路径长度(cost累加)

}

int w[200],sumw[200];

int fa[200];

int ui[maxn],vi[maxn],li[maxn],ci[maxn];

int toto=0;

void init()

{

         int i,j,k;

         scanf("%d",&n);

 

         for (i=1;i

         {

                   scanf("%d%d",&j,&k);

                   fa[j]=k;

                   scanf("%d",w+j);

         }

 

         memset(st,-1,sizeof(st));

         ee=0;

         toto=0;

         scanf("%d",&m);

         for (i=1;i<=m;i++)

                   scanf("%d%d%d%d",ui+i,vi+i,li+i,ci+i);

 

 

         for (j=1;j<=m;j++)

                   addedge(ui[j],vi[j],ci[j],li[j]);

         for (i=2;i<=n;i++)

                   addedge(fa[i],i,0,maxl);

 

         memset(sumw,0,sizeof(sumw));

         for (i=2;i<=n;i++)

                   sumw[fa[i]]+=w[i];

         w[1]=0;

         for (i=1;i<=n;i++)

                   if (sumw[i]

                   {

                            addedge(0,i,0,w[i]-sumw[i]);

                            toto+=w[i]-sumw[i];

                   }

                   else

                            if (sumw[i]>w[i])

                                     addedge(i,n+1,0,sumw[i]-w[i]);

}

int main()

{

         int cass,cas=0;

         for (scanf("%d",&cass);cass–;)

         {

                   cas++;

                   init();

                   printf("Case #%d: ",cas);

                   int cost=0;

                   flow=0;

                   while (1)

                   {

                            int k=spfa(0,n+1,n+2);

                            if (k

                                     cost+=k;

                            else

                                     break;

                   }

                   if (flow

                            puts("-1");

                   else

                            printf("%dn",cost);

         }

         return 0;

}

                  

Codeforces Beta Round #79 (finished)

A

Cnt[26]表示每个字母出现次数,然后sort一下,贪心地从个数少的开始删,删剩下的就是必须有的。

B

离散化以后就各种好搞- -。写圡了,按ti排序以后发现ti相同的那些转移有点问题。于是直接开个

map

CF上第一个hack…成功了叉了一个n^2都敢交的…

C

=_=经lcc指点后顿时泪流满面。

旋转原来那个东东,就相当于把一路上加的C向量和原来的向量都跟着一起旋转再叠加。

于是乎把目标的B向量旋转到4个方向,分别看看能不能用C旋转4个方向的向量拼出B-A.

然后C旋转4个方向的向量由于是90 180 270度的,所以可以只取其中两个垂直的。然后就是看是否存在整数(x,y)满足

x*C + Rotate90(C)*y = B-A

这个化出来以后就和两直线求交一个样- -,套个模板或者推一推就好了。

D

这个题要是当时看了就好了…卡了C以后没去搞这个…好经典的0_0

dfs的时候,按照这个函数对当前结点的儿子排下序

bool cmp(int x,int y){
     return Size[y]*Sum[x]}

其中Size表示子树下结点的数目,Sum[x]表示子树以及x与父亲相连的所有边的权和*2的值。

然后这样模拟算一算延迟的值就好了.

          sort(Q.begin(),Q.end(),cmp);
          long long tmp=0;
          for(int i=1;i              tmp+=Sum[Q[i-1]];
              ret+=tmp*Size[Q[i]];
          }

ret初始为从当前结点直接跑各个子树时的时间和…

代码:http://ideone.com/UsOfC

E

还不会捉。

题意就是

F[0,0]=(a[0]+b[0])%p

F[i,j]=max(F[i-1,j],F[i,j-1])+(a[i]+b[j])%p

输出F[n-1,m-1]以及取的方案

n,m<=20000.

时限15S

空间限制 45MB

 

=_=rating涨了一点点…

 

—————————————————————————————————————

E

看了官方题解。问题相当于找一个从(0,0)走到(n-1,m-1)的路线。pick完路上的权,最后权最大。只能向上或右走。

路径长度必然是(n-1 – 0)+(m-1 – 0)。然后把路径分为均匀的前后两半,于是可以确定一个最优解的中介点。递归下去。就得到了答案。

令r=n+m-2,那么复杂度这么算:r*r + 2*(r*r)/4 + 4*(r*r)/16 ….  k*(r*r)/(k*k)  … <= r*r + r*r

代码:http://ideone.com/XgoR1

 

update@8.7

[codeforces 85D]【平衡树】

【题意】

n个操作

每个操作可以是

add x  把x加进set里

del x   把x从set中删除

sum  令A[1..m]按递增序表示set中的函数。求Sum{A[i] | i%5==3}

【算法】

直接弄棵平衡树。每个结点维护下面几个域。 long long Sum[5] ,offset ,delta,key。

然后标记上下传就可以了,不错的平衡树练手题目。

尝试了一下struct封装好各种操作的Splay。。。感觉还挺舒服,但是写得爆长。。。

我感觉离散化以后线段树也可以搞。

或者直接建5棵平衡树。index变的时候就裂开然后再合并就好了。

【其它】

看了一下watashi飘逸的treap。

然后再看了一下最短的那个人。。。

修改用一个vector二分了个位置(lower_bound),然后直接insert erase。

然后统计直接for (i=3;i

特么坑爹啊!!!!!yandex.algorithm的题这样被人水过啊。

又想起NOI2003文本编辑器pascal那个不能吐槽的move=_=…特么比正解什么的都跑得快…

[codeforces 69C]【字符串模拟】

【链接】http://www.codeforces.com/problemset/problem/69/C

【其它】

其实这题很水- -,但是我STL套得很泪流满面…

比如这样

        cin >> S;

        S.erase(S.size()-1);

        Name=S;

        getline(cin,S);

        Del_dot(S);

        stringstream sin(S);

        int Num;

        Tv.clear();

        while (sin >> S >> Num)

              Tv.push_back(make_pair(S,Num));

        pf.push_back(make_pair(Name,Tv));

再比如这样

     for (vector< pair < string, vector < pair

搞了80行,压力太大了。

ym watashi的ruby和叉姐的python- –

 

[TopCoder SRM420 Div1 500pt RedIsGood]【数学期望】【动态规划】

【题意】

给你R张红牌,B张黑牌。

全翻过去。你每次可以选择翻开一张牌或者结束游戏。

翻开一张红牌你可以的1块钱,黑牌掉1块钱。

问假设你绝顶聪明,你得到的钱数是数学期望是多少?

【算法】

本来觉得红牌多就继续取,黑牌多不取了就是最优策略。

然后有个样例  11 12,期望居然>1。这才猛然发现可以通过见好就收的策略使得期望>0,于是就囧了。

解法是F[i][j]表示剩下i张红牌,j张黑牌,你绝顶聪明时的期望。

那么你怎么才叫聪明呢- -,当然是翻了以后,你继续聪明,得分的数学期望>0,那么就跑去翻,这样才叫聪明啊…

于是F[0][0]=0

F[i][j]=F[i-1][j]+1   (j=0)

F[i][j]=0                (i=0)

F[i][j]= max(  (F[i-1][j]+1)*(i/(i+j))  +  (F[i][j-1])*(j/(i+j))   ,   0   )

最后F[R][B]就是期望…

要用滚动数组优化一下。

【CODE】

 http://ideone.com/tfZ9a