USACO[Elite 2010 January Competition/gold]hayturn

博弈论。

CODE:

/*

PROG: hayturn

LANG: C++

ID: boleyn.2

*/

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-6-9

DESCRIPTION:

TITLE: Taking Turns [John Pardon, 2009]

CONTENT:

Farmer John has invented a new way of feeding his cows. He lays out

N (1 <= N <= 700,000) hay bales conveniently numbered 1..N in a

long line in the barn. Hay bale i has weight W_i (1 <= W_i <=

2,000,000,000). A sequence of six weights might look something like:

        17 5 9 10 3 8

A pair of cows named Bessie and Dessie walks down this line after

examining all the haybales to learn their weights. Bessie is the

first chooser. They take turns picking haybales to eat as they walk

(once a haybale is skipped, they cannot return to it). For instance,

if cows Bessie and Dessie go down the line, a possible scenario is:

* Bessie picks the weight 17 haybale

* Dessie skips the weight 5 haybale and picks the weight 9 haybale

* Bessie picks the weight 10 haybale

* Dessie skips the weight 3 haybale and picks the weight 8 haybale

Diagrammatically:

Bessie   |      |

        17 5 9 10 3 8

Dessie       |      |

This scenario only shows a single skipped bale; either cow can skip

as many as she pleases when it’s her turn.

Each cow wishes to maximize the total weight of hay she herself

consumes (and each knows that the other cow has this goal).

Furthermore, a cow will choose to eat the first bale of hay that

maximimizes her total weight consumed.

Given a sequence of hay weights, determine the amount of hay that

a pair of cows will eat as they go down the line of hay.

PROBLEM NAME: hayturn

INPUT FORMAT:

* Line 1: A single integer: N

* Lines 2..N+1: Line i+1 contains a single integer: W_i

SAMPLE INPUT (file hayturn.in):

6

17

5

9

10

3

8

OUTPUT FORMAT:

* Line 1: Two space-separated integers, the total weight of hay

        consumed by Bessie and Dessie respectively

SAMPLE OUTPUT (file hayturn.out):

27 17

*/

#include <fstream>

using std::ifstream;

using std::ofstream;

using std::endl;

#include <vector>

using std::vector;

 

class Application

{

      ifstream cin;

      ofstream cout;

      int N;

      vector<int> W;

      public:

      Application(const char* input,const char* output)

                        :cin(input),cout(output)

      {

                        std::ios::sync_with_stdio(false);

                        cin>>N;

                        W.resize(N);

                        for (vector<int>::iterator it=W.begin();

                                                   it!=W.end();it++)

                            cin>>*it;

      }

      ~Application()

      {

                    cin.close();

                    cout.close();

      }

      int run()

      {

          long long int max_me=0,max_not_me=0;

          for (int i=N-1;i>=0;i–)

              if (max_not_me+W[i]>=max_me)

              {

                 max_not_me+=W[i];

                 long long int swap=max_me;

                 max_me=max_not_me;

                 max_not_me=swap;

              }

          cout<<max_me<<” “<<max_not_me<<endl;         

          return 0;

      }

};

 

int main()

{

    Application app(“hayturn.in”,“hayturn.out”);

    return app.run();

}

 

北京大学2009年自主招生数学试题[第四、五题]


两道解不等式。

第四题:
已知对任意x均有a*cos(x)+b*cos(2x)>=-1恒成立,求a+b的最大值.
解:
令t=cos(x),-1<=t<=1
则a*cos(x)+b*cos(2x)=a*t+b*(2*t^2-1)>=-1
  a*t+b*(2*t^2-1)+1>=0
令f(t)=a*t+b*(2*t*t-1)+1=2*b*t^2+a*t+1-b
则f(t)>=0在[-1,1]恒成立
当b=0时,f(t)=a*t+1
f(-1)>=0,f(1)>=0,所以-1<=a<=1,这时a+b的最大值为1
当b!=0时(注:!=表示不等于)
满足f(-1)>=0
    f(1)>=0
    对称轴x=-a/4b
        -a/4b<=-1
        或-a/4b>=1
        或-1<-a/4b<1且f(-a/4b)>=0
恩,解得a+b<=2
所以最后a+b的最大值为2.

第五题:
某次考试共有333名学生做对了1000道题.做对3道及以下为不及格.6道及以上为优秀.问不及格和优秀的人数哪个多?
解:
假设有x人达优.
则x*6<=1000,没有达优的所有人的答对的题目的总数<=1000-x*6
所以及格了又没达优的人数*4<=没有达优的所有人的答对的题目的总数
所以及格了又没达优的人数<=没有达优的所有人的答对的题目的总数/4
又因为没及格的人数=333-x-及格了又没达优的人数
所以没及格的人数>=333-x-没有达优的所有人的答对的题目的总数/4>=333-x-(1000-x*6)/4
又因为x*6<=1000,所以x<=166,所以83>=x/2,所以83+x/2>=x
所以没及格的人数>=83+x/2>=x(当且仅当x=166时取等号)
所以当且仅当166做对个0道,1人做对4道,166人做对166道时不及格和优秀的人数一样多,其他情况不及格的多.

北京大学2009年自主招生数学试题[第二、三题]

证明题两道。

第二题:
已知一无穷等差数列中有3项:13,25,41.求证2009为数列中的一项.
解:
设a[n]=a[0]+d*n
又设a[x]=13,a[y]=25,a[z]=41,x,y,z为整数
所以x=(13-a[0])/d
    y=(25-a[0])/d
    z=(41-a[0])/d
又因为y+124*(z-y)=(2009-a[0])/d
所以(2009-a[0])/d是整数.
所以存在整数t,使得a[t]=2009
所以2009为数列中的一项.

第三题:
是否存在实数x使tan(x)+sqrt(3)与cot(x)+sqrt(3)同为有理数?(注:sqrt(x)=x的平方根)
解:
令t=tan(x),假设存在t使t+sqrt(3)和1/t+sqrt(3)都是有理数.
设有理数p=t+sqrt(3).
则1/t+sqrt(3)=1/(p-sqrt(3))+sqrt(3).
             =(p+sqrt(3))/(p^2-3)+sqrt(3)
             =(p+sqrt(3)*(1+p^2-3))/(p^2-3)
由于p为有理数,所以(1+p^2-3)为非零有理数,所以(p+sqrt(3)*(1+p^2-3))/(p^2-3)一定为无理数.
即,不存在x使tan(x)+sqrt(3)与cot(x)+sqrt(3)同为有理数.

北京大学2009年自主招生数学试题[第一题]

恩,基础的几何题。

第一题:
圆内接四边形ABCD.AB=1.BC=2.CD=3.DA=4.求圆半径.
解:
AB=1 BC=2 CD=3 DA=4
设AC=x,则(1^2+2^2-x^2)/(2*1*2)=-(3^2+4^2-x^2)/(2*3*4)
解得x^2=55/7
在三角形ABC中,AB=1,BC=2,AC^2=55/7
要求的半径即为三角形ABC的外接圆半径,
2*R=AC/sinC
易得R=sqrt(2310)/24.(注:sqrt(x)=x的平方根)

USACO[Holiday 2010 Bonus Competition/gold]cowpol

显然,对于一个党派,相距最远的两头牛中至少有一头是这个党派中深度最大的牛之一(这一点联系求树的直径,先随便从一点找最远,再从那儿找最远)。

所以每个党派的范围=max{最深的牛的深度+某头牛的深度-它们的最近公共祖先的深度*2,某头牛属于这个党派}。

问题的主要矛盾是LCA,然后,写了第一个Tarjan的LCA,由于数据太BT,要非递归,并且,即使这样下面的代码在Windows下无法编译(好像是因为开的内存太大了),但可以在USACO的测评系统下通过,所以在Linux下可以用的。

然后,LCA还有其它的算法可以做,有空再弄其它的,LCA这还是第一次写。

CODE:

/*

PROG: cowpol

LANG: C++

ID: boleyn.2

*/

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-6-4

DESCRIPTION:

TITLE: Cow Politics [Andre Kessler, 2009]

CONTENT:

Farmer John’s cows are living on N (2 <= N <= 200,000) different

pastures conveniently numbered 1..N. Exactly N-1 bidirectional cow

paths (of unit length) connect these pastures in various ways, and

each pasture is reachable from any other cow pasture by traversing

one or more of these paths (thus, the pastures and paths form a

graph called a tree).

The input for a particular set of pastures will specify the parent

node P_i (0 <= P_i <= N) for each pasture. The root node will specify

parent P_i == 0, which means it has no parent.

The cows have organized K (1 <= K <= N/2) different political parties

conveniently numbered 1..K. Each cow identifies with a single

political party; cow i identifies with political party A_i (1 <=

A_i <= K). Each political party includes at least two cows.

The political parties are feuding and would like to know how much

‘range’ each party covers. The range of a party is the largest

distance between any two cows within that party (over cow paths).

For example, suppose political party 1 consists of cows 1, 3, and

6, political party 2 consists of cows 2, 4, and 5, and the pastures

are connected as follows (party 1 members are marked as -n-):

  -3-

   |

  -1-

 / | \

2  4  5

      |

     -6-

The greatest distance between any two pastures of political party

1 is 3 (between cows 3 and 6), and the greatest distance for political

party 2 is 2 (between cows 2 and 4, between cows 4 and 5, and between

cows 5 and 2).

Help the cows determine party ranges.

TIME LIMIT: 2 seconds

MEMORY LIMIT: 64MB

PROBLEM NAME: cowpol

INPUT FORMAT:

* Line 1: Two space-separated integers: N and K

* Lines 2..N+1: Line i+1 contains two space-separated integers: A_i

        and P_i

SAMPLE INPUT (file cowpol.in):

6 2

1 3

2 1

1 0

2 1

2 1

1 5

OUTPUT FORMAT:

* Lines 1..K: Line i contains a single integer that is the range of

        party i.

SAMPLE OUTPUT (file cowpol.out):

3

2

*/

#include <fstream>

using std::ifstream;

using std::ofstream;

using std::endl;

#include <list>

using std::list;

namespace sj

{

          template<unsigned int size>

          class UFSET

          {

                int p[size];

                int rank[size];

                public:

                void MAKE_SET()

                {

                     for (int i=0;i<size;rank[i++]=0) p[i]=i;

                }

                int FIND_SET(int x)

                {

                    if (p[x]==x) return x;

                    else return p[x]=FIND_SET(p[x]);

                }

                void UNION(int x,int y)

                {

                     x=FIND_SET(x);

                     y=FIND_SET(y);

                     if (x==y) return;

                     if (rank[x]<rank[y]) p[x]=y;

                     else

                     {

                        p[y]=x;

                        if (rank[x]==rank[y]) rank[x]++;

                     }

                }

          };

}

using namespace sj;

 

class Application

{

      ifstream cin;

      ofstream cout;

      static const int MAXN=200000;

      int N,K;

      int A[MAXN+1],P[MAXN+1];

      int size[MAXN+1];

      int root;

      list<int> child[MAXN+1];

      int deep[MAXN+1];

      int deepest[MAXN+1];

      list<int> question[MAXN+1];

      UFSET<MAXN+1> set;

      bool visited[MAXN+1];

      int ancestor[MAXN+1];

      int dfs(int node,int depth=1,int father=0)

      {

          deep[node]=depth;

          if (deep[deepest[A[node]]]<depth) deepest[A[node]]=node;

          question[A[node]].push_back(node);

          for (list<int>::iterator i=child[node].begin();

                                   i!=child[node].end();i++)

              if (*i!=father) dfs(*i,depth+1,node);

      }

      int LCA(int root)

      {

          static int depth;

          static int _node[MAXN+1];

          static int _father[MAXN+1];

          static list<int>::iterator _i[MAXN+1];

         

          _node[depth]=root;

          _father[depth]=0;

          _i[depth]=child[_node[depth]].begin();

          ancestor[_node[depth]]=_node[depth];

         

          for (;;)

          {

              int& node=_node[depth];

              int& father=_father[depth];

              list<int>::iterator& i=_i[depth];

             

              if (*i==father) i++;             

              if (i!=child[node].end())

              {

                 depth++;

                 _node[depth]=*i;

                 _father[depth]=node;

                 _i[depth]=child[_node[depth]].begin();

                 ancestor[_node[depth]]=_node[depth];

              }

              else

              {

                  visited[node]=true;

                  if (node==deepest[A[node]])

                  {

                     for (list<int>::iterator i=question[A[node]].begin();

                                              i!=question[A[node]].end();i++)

                         if (visited[*i])

                     {

                         int get=deep[node]+deep[*i]

                                 -deep[ancestor[set.FIND_SET(*i)]]*2;

                         if (size[A[node]]<get) size[A[node]]=get;

                     }

                  }

                  else if (visited[deepest[A[node]]])

                  {

                       int get=deep[node]+deep[deepest[A[node]]]

                               -deep[ancestor[set.FIND_SET(deepest[A[node]])]]*2;

                       if (size[A[node]]<get) size[A[node]]=get;

                  }

                  depth–;

                  if (depth<0) break;

                  set.UNION(_node[depth],*_i[depth]);

                  ancestor[set.FIND_SET(*_i[depth])]=_node[depth];

                  _i[depth]++;

              }

          }

      }

      /*

      int LCA(int node,int father=0)

      {

          ancestor[node]=node;

          for (list<int>::iterator i=child[node].begin();

                                   i!=child[node].end();i++)

              if (*i!=father)

              {

                 LCA(*i,node);

                 set.UNION(node,*i);

                 ancestor[set.FIND_SET(*i)]=node;

              }

          visited[node]=true;

         

          if (node==deepest[A[node]])

          {

             for (list<int>::iterator i=question[A[node]].begin();

                                      i!=question[A[node]].end();i++)

                 if (visited[*i])

                 {

                    int get=deep[node]+deep[*i]

                            -deep[ancestor[set.FIND_SET(*i)]]*2;

                    if (size[A[node]]<get) size[A[node]]=get;

                    //cout<<“LCA”<<node<<” “<<*i

                    //    <<“=”<<ancestor[set.FIND_SET(*i)]<<endl;

                 }

          }

          else if (visited[deepest[A[node]]])

          {

               int get=deep[node]+deep[deepest[A[node]]]

                       -deep[ancestor[set.FIND_SET(deepest[A[node]])]]*2;

               if (size[A[node]]<get) size[A[node]]=get;

               //cout<<“LCA”<<node<<” “<<deepest[A[node]]

               //    <<“=”<<ancestor[set.FIND_SET(deepest[A[node]])]<<endl;

          }

      }

      */

      public:

      Application(const char* input,const char* output)

                        :cin(input),cout(output)

      {

                        cin>>N>>K;

                        for (int i=1;i<=N;i++)

                            cin>>A[i]>>P[i];

      }

      ~Application()

      {

                    cin.close();

                    cout.close();

      }

      int run()

      {

          for (int i=1;i<=N;i++)

          {

              if (P[i]) child[P[i]].push_back(i);

              else root=i;

              child[i].push_back(P[i]);

          }

          dfs(root);

          set.MAKE_SET();

          LCA(root);

          for (int i=1;i<=K;i++)

              cout<<size[i]<<endl;

          return 0;

      }

};

 

int main()

{

    static

    Application app(“cowpol.in”,“cowpol.out”);

    return app.run();

}

 

USACO[Elite 2010 U S Open Competition/gold]

恩,第一题动态规划,用单调队列优化到O(n),第二题,树形动规。

然后重点第三题,这是APIO2010中的第三题(信号覆盖/signaling)也要用到的东西,统计平面中不包含某一点的三角形的个数。

看图:

USACO[Elite 2010 U S Open Competition/gold]解题报告 - 天之骄子 - 天之骄子的家
假设我们要求平面中不包含蓝色点的三角形个数,我们可以知道这样的三角形的三个点必定在蓝色点的一侧,所以我们可以用扫描法。
先将点按极角排序,然后对每一个点,找出在它逆时针方向180度以内(不包含180度)的点的个数。
那么,可以组合出C(个数,2),即随便选两个点和这个点搭配。
然后将所有组合加起来,就得到了平面中不包含某一点的三角形的个数。
下面给出上图的说明:
对a,b,c在逆时针方向180度以内(因为a和d刚好成180度角,所以不算d),C(2,2)=1;
对b,c,d,e在逆时针方向180度以内,C(3,2)=3;
对c,d,e,f在逆时针方向180度以内,C(3,2)=3;
对d,e,f,g在逆时针方向180度以内,C(3,2)=3;
对e,f,g,a在逆时针方向180度以内,C(3,2)=3;
对f,g,a,b在逆时针方向180度以内,C(3,2)=3;
对g,a,b,c在逆时针方向180度以内,C(3,2)=3。
总共19个三角形不包含蓝点。
包含蓝点的三角形=所有三角形的个数-不包含蓝点的三角形数目。
对于第三题,由于数据的原因(没有两点的连线过原点)所以
所有三角形的个数=C(总点数,3)-退化成一条线的三角形个数,
不包含蓝点的三角形数目=不包含蓝点的三角形数目(这里的三角形可以是退化的)-退化成一条线的三角形个数,
所以
答案=C(总点数,3)-不包含蓝点的三角形数目(这里的三角形可以是退化的)。
我要去考数学了,代码时间。
CODE:

/*

PROG: hop

LANG: C++

ID: boleyn.2

*/

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-6-3

DESCRIPTION:

TITLE: Cow Hopscotch [John Pardon, 2010]

CONTENT:

The cows have reverted to their childhood and

are playing a game similar to human hopscotch.

Their hopscotch game features a line of N (3 <=

N <= 250,000) squares conveniently labeled 1..N

that are chalked onto the grass.

Like any good game, this version of hopscotch

has prizes!  Square i is labeled with some

integer monetary value V_i (-2,000,000,000 <=

V_i <= 2,000,000,000). The cows play the game to

see who can earn the most money.

The rules are fairly simple:

    * A cow starts at square “0” (located just before square 1; it

      has no monetary value).

    * She then executes a potentially empty sequence of jumps toward

      square N. Each square she lands on can be a maximum of K (2

      <= K <= N) squares from its predecessor square (i.e., from

      square 1, she can jump outbound to squares 2 or 3 if K==2).

    * Whenever she wishes, the cow turns around and jumps back

      towards square 0, stopping when she arrives there. In addition

      to the restrictions above (including the K limit), two

      additional restrictions apply:

      * She is not allowed to land on any square she touched on her

        outbound trip (except square 0, of course).

      * Except for square 0, the squares she lands on during the

    return trip must directly precede squares she landed on

    during the outbound trip (though she might make some larger

    leaps that skip potential return squares altogether).     

She earns an amount of money equal to the sum of the monetary values

of all the squares she jumped on. Find the largest amount of cash

a cow can earn.

By way of example, consider this five box cow-hopscotch course where

K has the value 3:

Square Num:    0      1      2      3      4      5      6

             +—+  +—+  +—+  +—+  +—+  +—+  +—+

             |///|–|   |–|   |–|   |–|   |–|   |–|   |

             +—+  +—+  +—+  +—+  +—+  +—+  +—+

     Value:          0      1      2     -3      4      5

One (optimal) sequence Bessie could jump (shown with respective

bracketed monetary values) is: 1[0], 3[2], 6[5], 5[4], 2[1], 0[0]

would yield a monetary total of 0+2+5+4+1+0=12.

If Bessie jumped a sequence beginning with 0, 1, 2, 3, 4, … then

she would be unable to return since she could not legally jump back

to an untouched square.

PROBLEM NAME: hop

INPUT FORMAT:

* Line 1: Two space separated integers: N and K

* Lines 2..N+1: Line i+1 contains a single integer: V_i

SAMPLE INPUT (file hop.in):

6 3

0

1

2

-3

4

5

OUTPUT FORMAT:

* Line 1: A single line with a single integer that is the maximum

        amount of money a cow can earn

SAMPLE OUTPUT (file hop.out):

12

*/

#include <stdio.h>

#include <iostream>

using std::cin;

using std::cout;

using std::endl;

 

const int MAXN=250000;

const long long int oo=1000000000000000000ll;

int N,K;

int V[MAXN+1];

 

long long int _sum[MAXN+2];

long long int _f[MAXN+2];

long long int answer;

 

int main()

{

    freopen(“hop.in”,“r”,stdin);

    freopen(“hop.out”,“w”,stdout);

    scanf(“%d %d\n”,&N,&K);

    for (int i=1;i<=N;i++)

        scanf(“%d\n”,&V[i]);

   

    long long int* sum=_sum+1;

    long long int* f=_f+1;

   

    for (int i=1;i<=N;i++)

        if (V[i]>0) sum[i]=sum[i-1]+V[i];

        else sum[i]=sum[i-1];

   

    answer=-oo;

   

    int head,tail;

    int q[MAXN];

    f[q[head=tail=0]=-1]=0;

    for (int i=0;i<=N;i++)

    {

        long long int get=f[q[head]]-sum[q[head]+1]+sum[i-1]+V[i];

        if (get>answer) answer=get;

       

        while (q[head]+K<i) head++;

        if (i!=N) f[i]=f[q[head]]-sum[q[head]+1]+sum[i-1]+V[i]+V[i+1];

       

        while (head<=tail&&f[q[tail]]-sum[q[tail]+1]<f[i]-sum[i+1]) tail–;

        q[++tail]=i;

    }

   

    cout<<answer<<endl;

   

    fclose(stdin);

    fclose(stdout);

    return 0;

}

 

/*

PROG: slide

LANG: C++

ID: boleyn.2

*/

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-4-23

DESCRIPTION:

TITLE: Water Slides [John Pardon, 2010]

CONTENT:

Inspired by the new water park at Machu

Picchu in Peru, Farmer John has decided

to build one for the cows. Its biggest

attraction is to be a giant water slide

of a peculiar design.

The superslide comprises E (1 <= E <=

150,000) mini slides connecting V (2 <=

V <= 50,000) small pools conveniently

labeled 1..V. Every mini slide must be

traversed in its proper direction and

may not be traversed backwards. The

cows start at pool number 1 and

traverse successive mini slides until

they end up in the pool number V, the

final pool. Every pool (except V, the

last one and 1, the first one)

includes at least one mini slide

entering it and at least one

(different) mini slide for exiting

it.  Furthermore, a cow can reach the

end of the ride (pool V) from any

pool by going down a sequence of mini

slides. Finally, since this is a

slide, it is not possible to leave a

pool and then encounter that pool

again after traversing some set of

mini slides.

Each mini slide i runs from pool P_i to pool Q_i (1 <= P_i <= V; 1

<= Q_i <= V; P_i != Q_i) and has an associated fun value F_i (0 <=

F_i <= 2,000,000,000). Bessie’s total fun for any given trip down

the superslide is the sum of the fun values of all the mini slides

traversed.

Bessie naturally wants to have as much fun as possible, given the

long time that she spends in the slide’s queue waiting for the ride.

Generally, she carefully chooses which mini slide to follow out of

each pool. She is a cow, however, and no more than K (1 <= K <= 10)

times as she splashes down the slide, she loses control and follows

a random mini slide out of a pool (this can even happen on pool 1).

If Bessie chooses so as to maximize her fun in the worst case, how

much fun is she guaranteed to have for a given super-slide?

By way of example, consider a small park that has 3 pools (pool

id’s shown in brackets) and four mini slides; K has the value 1

(fun values shown outside of brackets):

          [1]

         /   \

   5 -> /     \ <- 9

       /       \

     [2]—3—[3]

        \__5__/

She alway starts at pool 1 and ends and pool 3. If she had her way,

she’d ride direct from pool 1 to pool 2 and then on the higher-fun

mini slide (with fun value 5) to slide 3 for a total fun value of

5+5=10. But, if she loses control at pool 1, she might slide directly

from pool 1 to pool 3 for total fun 9. If she loses control at pool

2, she could reduce her total fun to just 5+3 = 8.

Bessie wants to find the most fun she can have so she strives to

choose 1->3 for a total fun of 9. If she loses control at pool 1

and ends up on mini slide 1->2, she knows she will not lose control

at pool 2 and will end up with fun 10. Thus, she knows her minimum

fun will always be at least 9.

PROBLEM NAME: slide

INPUT FORMAT:

* Line 1: Three space separated integers: V, E, and K

* Lines 2..E + 1: Line i+1 contains three space separated integers:

        P_i, Q_i, and F_i

SAMPLE INPUT (file slide.in):

3 4 1

2 3 5

1 2 5

1 3 9

2 3 3

OUTPUT FORMAT:

* Line 1: A single line with a single integer that is the minimum fun

        that Bessie can guarantee she can have.

SAMPLE OUTPUT (file slide.out):

9

*/

#include <stdio.h>

#include <iostream>

using namespace std;

#include <vector>

using std::vector;

 

const long long int oo=1000000000000000000ll;

const long long int MAXV=50000,MAXE=150000,MAXK=10;

long long int V,E,K;

long long int P[MAXE],Q[MAXE],F[MAXE];

bool calced[MAXV+1][MAXK+1];

vector<int> child[MAXV+1],length[MAXV+1];

long long int value[MAXV+1][MAXK+1];

long long int answer;

 

long long int min(long long int a,long long int b)

{

     return a<b?a:b;

}

long long int max(long long int a,long long int b)

{

     return a>b?a:b;

}

long long int dp(int node,int k)

{

     if (!calced[node][k])

     {

        calced[node][k]=true;

        for (int i=0;i<child[node].size();i++)

            value[node][k]=max(value[node][k],

                               dp(child[node][i],k)+length[node][i]);

        if (k>0)

           for (int i=0;i<child[node].size();i++)

           {

               value[node][k]=min(value[node][k],

                                  dp(child[node][i],k-1)+length[node][i]);

           }

     }

     return value[node][k];

}

void print(long long int long_long_int)

{

     if (long_long_int>=10)

        print(long_long_int/10);

     printf(“%d”,int(long_long_int%10));

}

 

int main()

{

    freopen(“slide.in”,“r”,stdin);

    freopen(“slide.out”,“w”,stdout);

    scanf(“%d %d %d\n”,&V,&E,&K);

    for (int i=0;i<E;i++)

        scanf(“%d %d %d\n”,&P[i],&Q[i],&F[i]);

   

    for (int i=0;i<E;i++)

    {

        child[P[i]].push_back(Q[i]);

        length[P[i]].push_back(F[i]);

    }   

    answer=dp(1,K);

   

    /*

    printf(“%lld\n”,answer); //for Linux/Unix

    printf(“%I64d\n”,answer); //for Windows

    */

    //for anywhere

    print(answer);

    printf(“\n”);

   

    fclose(stdin);

    fclose(stdout);

    return 0;

}

 

/*

PROG: tricount

LANG: C++

ID: boleyn.2

*/

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-6-3

DESCRIPTION:

TITLE: Triangle Counting [Tom Conerly, 2010]

CONTENT:

Bessie is standing guard duty after

the big bad wolf was spotted stalking

cows over at Farmer Don’s spread.

Looking down from her guard tower in

utter boredom, she’s decided to

perform intellectual exercises in

order to keep awake.

After imagining the field as an X,Y

grid, she recorded the coordinates of

the N (1 <= N <= 100,000)

conveniently numbered 1..N cows as

X_i,Y_i (-100,000 <= X_i <= 100,000;

-100,000 <= Y_i <= 100,000; 1 <= i <=

N). She then mentally formed all possible triangles that could be

made from subsets of the entire set of cow coordinates. She counts

a triangle as ‘golden’ if it wholly contains the origin (0,0). The

origin does not fall on the line between any pair of cows. Additionally,

no cow is standing exactly on the origin.

Given the list of cow locations, calculate the number of ‘golden’

triangles that contain the origin so Bessie will know if she’s doing

a good job.

By way of example, consider 5 cows at these locations:

             -5,0   0,2   11,2   -11,-6   11,-5

Below is a schematic layout of the field from Betsy’s point of view:

          …………|…………

          …………*……….*.

          …………|…………

          ——-*—-+————

          …………|…………

          …………|…………

          …………|…………

          …………|…………

          …………|……….*.

          .*……….|…………

          …………|…………

All ten triangles below can be formed from the five points above:

By inspection, 5 of them contain the origin and hence are ‘golden’.

PROBLEM NAME: tricount

INPUT FORMAT:

* Line 1: A single integer: N

* Lines 2..N+1: Each line contains two integers, the coordinates of a

        single cow: X_i and Y_i

SAMPLE INPUT (file tricount.in):

5

-5 0

0 2

11 2

-11 -6

11 -5

OUTPUT FORMAT:

* Line 1: A single line with a single integer that is the count of the

        number of times a triangle formed by the cow locations

        contains the origin

SAMPLE OUTPUT (file tricount.out):

5

*/

#include <fstream>

using std::ifstream;

using std::ofstream;

using std::endl;

#include <utility>

using std::pair;

using std::make_pair;

#define Point pair<int,int>

#define x first

#define y second

 

struct Compare

{

       static

       inline

       long long int cross(const Point& a,const Point& b)

       {

            return (long long int)(a.x)*(long long int)(b.y)-(long long int)(b.x)*(long long int)(a.y);

       }

       static

       inline

       bool less(const Point& a,const Point& b)

       {

            return cross(a,b)>0;

       }

      

       static

       void sort(Point* l,Point* r)

       {

            Point* i=l;

            Point* j=r;

            Point mid=*(l+((r-l)>>1));

            while (i<=j)

            {

                  while (less(*i,mid)) i++;

                  while (less(mid,*j)) j–;

                  if (i<=j)

                  {

                     Point s=*i;

                     *i=*j;

                     *j=s;

                     i++;

                     j–;

                  }

            }

            if (l<j) sort(l,j);

            if (i<r) sort(i,r);

       }

};

 

class Application

{

      ifstream cin;

      ofstream cout;

      static const int MAXN=100000;

      long long int N;

      Point p[MAXN];

      public:

      Application(const char* input,const char* output)

                        :cin(input),cout(output)

      {

                        cin>>N;

                        for (int i=0;i<N;i++)

                            cin>>p[i].x>>p[i].y;

      }

      ~Application()

      {

                    cin.close();

                    cout.close();

      }

      int run()

      {

          Compare compare;

          compare.sort(p,p+N-1);

          long long int result=0;

          for (int i=0,j=0;i<N;i++)

          {

              while (compare.less(p[i],p[(j+1)%N])) j=(j+1)%N;

              int get=(j-i+N)%N;

              if (get>=2) result+=((get)*(get-1))>>1;

          }

          cout<<(N*(N-1)*(N-2))/(3*2*1)-result<<endl;

          return 0;

      }

};

 

int main()

{

    Application app(“tricount.in”,“tricount.out”);

    return app.run();

}

 

NOI2009[二叉查找树/treapmod]

动态规划,看了题解做的,没什么可讲,推荐看这份题解

CODE:

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-5-30

DESCRIPTION:

$DESCRIPTION

*/

#include <stdio.h>

#include <algorithm>

using std::sort;

using std::min;

 

class Application

{

      FILE* in;

      FILE* out;

      static const int MAXN=70;

      typedef struct{int key,weight,p;} Node;

      int N,K;

      Node node[MAXN];

      static bool less_weight(const Node& a,const Node& b)

      {

             return a.weight<b.weight;

      }

      static bool less_key(const Node& a,const Node& b)

      {

             return a.key<b.key;

      }

      int dp(int i,int j,int w)

      {         

          static int f[MAXN][MAXN][MAXN+1];

          static bool calced[MAXN][MAXN][MAXN+1];

          if (i>j) return 0;

          if (!calced[i][j][w])

          {

             calced[i][j][w]=true;

             f[i][j][w]=~(1<<31);

             int get;

             for (int k=i;k<=j;k++)

             {

                 get=dp(i,k-1,w)+dp(k+1,j,w)+sum(i,j)+K;

                 f[i][j][w]=min(f[i][j][w],get);                 

                 if (node[k].weight>=w)

                 {

                    int _w=node[k].weight;

                    get=dp(i,k-1,_w)+dp(k+1,j,_w)+sum(i,j);

                    f[i][j][w]=min(f[i][j][w],get);

                 }

             }

          }

          return f[i][j][w];

      }

      int sum(int i,int j)

      {

          static bool calced;

          static int f[MAXN+1];

          if (!calced)

          {

             calced=true;

             for (int i=0;i<N;i++)

                 f[i+1]=f[i]+node[i].p;

          }

          return f[j+1]-f[i];

      }

      public:

      Application(const char* input=0,const char* output=0)

                        :in(input?fopen(input,“r”):stdin),

                         out(output?fopen(output,“w”):stdout)

      {

                         fscanf(in,“%d%d”,&N,&K);

                         for (int i=0;i<N;i++)

                             fscanf(in,“%d%”,&node[i].key);

                         for (int i=0;i<N;i++)

                             fscanf(in,“%d”,&node[i].weight);

                         for (int i=0;i<N;i++)

                             fscanf(in,“%d”,&node[i].p);

      }

      ~Application()

      {

                    fclose(in);

                    fclose(out);

      }

      int run()

      {

          sort(node,node+N,less_weight);

          for (int i=0;i<N;i++)

              node[i].weight=i+1;

          sort(node,node+N,less_key);

         

          int answer=min(dp(0,N-1,1),dp(0,N-1,0));

          fprintf(out,“%d\n”,answer);

          return 0;

      }

};

 

int main()

{

    Application app(“treapmod.in”,“treapmod.out”);

    return app.run();

}

 

HNOI2008[玩具装箱]

动态规划,四边形不等式优化,这道题还可以斜率优化。

CODE:

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-5-29

DESCRIPTION:

湖南2008年省选 玩具装箱

*/

#include <stdio.h>

 

class Application

{

      FILE* in;

      FILE* out;

      static const int MAXN=50000;

      int N,L;

      int c[MAXN];

      void print_long_long_int(long long int number)

      {

           if (number>=10) print_long_long_int(number/10);

           fprintf(out,“%d”,number%10);

      }

      public:

      Application(const char* input=0,const char* output=0)

                        :in(input?fopen(input,“r”):stdin),

                         out(output?fopen(output,“w”):stdout)

      {

                         fscanf(in,“%d%d”,&N,&L);

                         for (int i=0;i<N;i++)

                             fscanf(in,“%d”,c+i);

      }

      ~Application()

      {

                    fclose(in);

                    fclose(out);

      }

      int run()

      {

          long long int sum[MAXN+1];

          sum[0]=0;

          for (int i=0;i<N;i++)

              sum[i+1]=sum[i]+c[i];

          long long int f[MAXN+1];

          /*

          f[0]=0;

          for (int i=1;i<=N;i++)

          {

              f[i]=1000000000000000000ll;

              for (int j=0;j<i;j++)

              {

                  long long int x=i-j-1+sum[i]-sum[j]-L;

                  x*=x;

                  if (f[i]>f[j]+x)

                     f[i]=f[j]+x;

              }

          }

          */

          int head,tail;

          int begin[MAXN+1],end[MAXN+1],best[MAXN+1];

          f[0]=0;

          head=tail=0;

          begin[tail]=0;

          end[tail]=N;

          best[tail]=0;

          for (int i=1;i<=N;i++)

          {

              while (end[head]<i) head++;

              int j=best[head];

              long long int x=i-j-1+sum[i]-sum[j]-L;

              f[i]=f[j]+x*x;

              #define value(i,j) \

                      (f[j]+(i-j-1+sum[i]-sum[j]-L)*(i-j-1+sum[i]-sum[j]-L))

              while (head<tail

                     &&value(begin[tail],best[tail])>=value(begin[tail],i))

                     end[tail-1]=end[tail],tail–;

              int l=begin[tail],r=end[tail]+1;

              while (l+1!=r)

              {

                    int mid=(l+r)>>1;

                    if (value(mid,best[tail])<value(mid,i)) l=mid;

                    else r=mid;

              }

              if (l+1<=end[tail])

              {

                 tail++;

                 begin[tail]=l+1;

                 end[tail]=end[tail-1];

                 best[tail]=i;

                 end[tail-1]=l;

              }

          }

          print_long_long_int(f[N]);

          fprintf(out,“\n”);

          return 0;

      }

};

 

int main()

{

    Application app;

    return app.run();

}

 

NOI2009[诗人小G/poet]

动态规划,方程是f[i]=min{f[j]+|sum[i]-sum[j]+i-j-1-L|^P}。

朴素的不能AC,要超时,然后要用四边形不等式优化,优化到O(nlogn)。

恩,四边形不等式优化正在研究中。

CODE:

/*

PROGRAM: $PROGRAM

AUTHOR: Su Jiao

DATE: 2010-5-27

DESCRIPTION:

$DESCRIPTION

*/

#include <stdio.h>

#include <string.h>

#include <math.h>

 

class Application

{

      FILE* in;

      FILE* out;

      static const int MAXLENGTH=50;

      static const int MAXN=100000;

      static const long long int oo=1000000000000000000ll;

      typedef char string[MAXLENGTH+1];

      int T;

      int N,L,P;

      string s[MAXN+2];

      long long int sum[MAXN+2];

      long long int f[MAXN+2];

      int pre[MAXN+2];

      int top;

      int stack[MAXN+2];

      int head,tail;

      int begin[MAXN+2],end[MAXN+2],best[MAXN+2];

      void print_long_long_int(long long int number)

      {

           if (number>=10) print_long_long_int(number/10);

           fprintf(out,“%d”,number%10);

      }

      static long long int abs(long long int n)

      {

             return n>0?n:-n;

      }

      static long long int power(long long int b,long long int p)

      {

             long long int get=1;

             while (p)

             {

                   if (p&1) get*=b;

                   b*=b;

                   p>>=1;

             }

             return get;

      }

      void solve()

      {

           sum[0]=0;

           for (int i=1;i<=N;i++)

               sum[i]=sum[i-1]+strlen(s[i]);

           //f[i]=min{f[j]+|sum[i]-sum[j]+i-j-1-L|^P}

           /*

           f[0]=0;

           for (int i=1;i<=N;i++)

           {

               double min=oo*2;

               for (int j=0;j<i;j++)

               {

                   double get=f[j]+pow(fabs(sum[i]-sum[j]+i-j-1-L),P);

                   if (get<min)

                   {

                      min=get;

                      pre[i]=j;

                   }

               }

               if (f[pre[i]]+pow(fabs(sum[i]-sum[pre[i]]+i-pre[i]-1-L),P)<oo*2)

               {

                  f[i]=f[pre[i]]+power(abs(sum[i]-sum[pre[i]]+i-pre[i]-1-L),P);

                  if (f[i]>oo) f[i]=oo+1;

               }

               else f[i]=oo+1;

           }

           */

           f[0]=0;

           head=tail=0;

           begin[tail]=0;

           end[tail]=N;

           best[tail]=0;

           for (int i=1;i<=N;i++)

           {

               while (end[head]<i) head++;

               pre[i]=best[head];

              

               if (f[pre[i]]+pow(fabs(sum[i]-sum[pre[i]]+i-pre[i]-1-L),P)<oo*2)

               {

                  f[i]=f[pre[i]]+power(abs(sum[i]-sum[pre[i]]+i-pre[i]-1-L),P);

                  if (f[i]>oo) f[i]=oo+1;

               }

               else f[i]=oo+1;

               #define value(now,pre) \

                       f[pre]+pow(fabs(sum[now]-sum[pre]+now-pre-1-L),P)

               while (head<tail

                      &&value(begin[tail],i)<value(begin[tail],best[tail]))

                      end[tail-1]=end[tail],tail–;

               int l=begin[tail],r=end[tail]+1;

               while (l+1!=r)

               {

                     int mid=(l+r)>>1;

                     if (value(mid,best[tail])<value(mid,i)) l=mid;

                     else r=mid;

               }

               if (l+1<=end[tail])

               {

                  tail++;

                  begin[tail]=l+1;

                  end[tail]=end[tail-1];

                  best[tail]=i;

                  end[tail-1]=l;

               }

               #undef value

           }

           if (f[N]>oo) fprintf(out,“Too hard to arrange\n”);

           else

           {

               print_long_long_int(f[N]);

               fprintf(out,“\n”);

               stack[top=0]=N;

               while (stack[top])

                     stack[top+1]=pre[stack[top]],top++;

              

               for (int i=top;i>0;i–)

                   for (int j=stack[i]+1;j<=stack[i-1];j++)

                       fprintf(out,“%s%c”,s[j],j==stack[i-1]?’\n’:’ ‘);

           }

           fprintf(out,“——————–\n”);

          

      }

      public:

      Application(const char* input,const char* output)

                        :in(fopen(input,“r”)),out(fopen(output,“w”))

      {

                        fscanf(in,“%d”,&T);

      }

      ~Application()

      {

                    fclose(in);

                    fclose(out);

      }

      int run()

      {

          for (int i=0;i<T;i++)

          {

              fscanf(in,“%d%d%d”,&N,&L,&P);

              for (int i=1;i<=N;i++)

                  fscanf(in,“%s”,s+i);

              solve();

          }

      }

};

 

int main()

{

    static

    Application app(“poet.in”,“poet.out”);

    return app.run();

}

 

斜率优化的具体操作和证明[信息学资料]

这里是斜率优化的具体操作和证明,恩,顺便附上一个例子,APIO2010第一题commando/特别行动队的解题思路。

 

前言:
对于一个动态规划模型f[i]=max{f[j]+g(j,i)}(这里只讨论max,min的可以想成-max{什么什么})。
我们称对于阶段i决策x的价值为value(x)=f[x]+g(x,i)。
那么如果value(j)-value(k)>0,我们就说j比k优。
如果j<k时,value(j)-value(k)>0可以化成K(j,k)>H(i)的形式(这时K(j,k)>H(i)等价于j比k优),且H(i)是单调递增的,我们就可以用斜率优化了。
我们需要维护一个单调队列使得K(队中相邻的两个决策)递增。

具体操作:
Line
0   |Type f[XX..YY];
1   |Deque q;
2   |f[边界]:=边界值;
3   |q.push_back(边界);
4   |
5   |for i:=XX to YY do
6   |begin
7   |    while q中至少有两个决策 and K(队首,队首的后一个)<=H(i) do q.pop_front();
8   |    f[i]=value(队首);
9   |    while q中至少有两个决策 and K(队尾的前一个,队尾)>=K(队尾,i) do q.pop_back();
10  |    q.push_back(i);
11  |end;

 

证明(我用《算法导论》中的循环不变式来证明):
初始化:在0到3行的代码执行后,f[边界]=边界值,队中没有相邻的两个决策,所以显然是正确的。
保持:
/*开始*/
在5到11行代码中,涉及到三个操作,除去队首无用决策(第7行),计算f[i](第8行),除去队尾无用决策并加入决策i(第9到10行),我们分别证明。
1.除去队首无用决策
由于K(队中相邻的两个决策)在这次操作前是递增的,所以执行第7行代码后,K(队中相邻的两个决策)>H(i),即队中前一个元素比后一个元素优,或者q中只有一个决策(而它显然最优),又因为H(i)递增,所以被pop掉的决策总是前一个没有后一个优,并且都没有新的队首优,所以pop他们是正确的。
综上所述,这一步是正确的。
2.计算f[i]
由于除去队首无用决策后,队中前一个元素比后一个元素优,所以最优的决策显然在队首,所以f[i]:=value(队首)这个操作显然正确。
3.除去队尾无用决策并加入决策i
如果q中只有一个决策,那么我们将i直接加入队尾,显然K(队中相邻的两个决策)是递增的。
如果q中有多于一个决策,那么如果K(队尾的前一个,队尾)>=K(队尾,i),那么在某个阶段i’:
1)如果K(队尾的前一个,队尾)>=H(i’)>=K(队尾,i),那么”队尾”没有”队尾的前一个”优,也没有”i”优,所以”队尾”不可能成为最优的决策,我们pop它,显然正确;
2)如果K(队尾的前一个,队尾)>=K(队尾,i)>=H(i’),那么”队尾”没有”队尾的前一个”优,只是比”i”优,所以”队尾”不可能成为最优的决策,我们pop它,显然正确;
3)如果H(i’)>=K(队尾的前一个,队尾)>=K(队尾,i),那么”队尾”没有”i”优,只是比”队尾的前一个”优,所以”队尾”不可能成为最优的决策,我们pop它,显然正确。
综上所述,如果K(队尾的前一个,队尾)>=K(队尾,i),pop队尾是一个正确的举动。
如果K(队尾的前一个,队尾)<K(队尾,i),那么我们停止while,然后q.push_back(i),这时保持了K(队中相邻的两个决策)的单调性,是我们想要的,所以正确。
/*结束*/
终止:当算法结束后,f[YY]已经求出,即我们需要的最优值已经求出,这意味这算法是正确的。

例子(APIO2010第一题commando/特别行动队):
恩,输入n,a,b,c,x[1..n]。
预处理sum[0]:=0,sum[i]:=sum[i-1]+x[i]。
动规方程是f[i]=max{f[j]+g(j,i)},这里g(j,i)=a*(sum[i]-sum[j])*(sum[i]-sum[j])+b*(sum[i]-sum[j])+c。
然后value(x)=f[x]+g(x,i)=f[x]+a*(sum[i]-sum[x])*(sum[i]-sum[x])+b*(sum[i]-sum[x])+c。
如果j<k时,value(j)-value(k)>0可以化成K(j,k)>H(i)的形式(这时K(j,k)>H(i)等价于j比k优),且H(i)是单调递增的,我们就可以用斜率优化了。
当j<k时,对value(j)-value(k)>0变形,得:
2*a*sum[i]*(sum[k]-sum[j])>f[k]-f[j]+b*(sum[j]-sim[k])+a*(sum[k]*sum[k]-sum[j]*sum[j])
sum[i]<(f[k]-f[j]+b*(sum[j]-sim[k])+a*(sum[k]*sum[k]-sum[j]*sum[j]))  /  (2*a*(sum[k]-sum[j])) /*因为a<0,sum[k]-sum[j]>0,所以反号*/
这时,我们看到了曙光!!
K(j,k)=(f[k]-f[j]+b*(sum[j]-sim[k])+a*(sum[k]*sum[k]-sum[j]*sum[j]))  /  (2*a*(sum[k]-sum[j]))
H(i)=sum[i]
满足K(j,k)>H(i),H(i)递增,所以我们可以斜率优化了,恩,就是这样,代码见这里