SDOI2009[Elaxia的路线]

先求出那些在公共最短路上的边,并规定方向,对于边<u,v>,d(x1,u)<d(x1,v)。

然后这些边就组成了一个有向无环图,现在要求的就是这个图上的最长链。

就用动态规划做。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-26

DESCRIPTION:

山东2009年省选 Elaxia的路线

*/

#include <stdio.h>

#include <string.h>

 

const int MAXN=1500;

const int oo=0x7f7f7f7f;

int N,M;

int x1,y1,x2,y2;

int map[MAXN+2][MAXN+2];

int dx1[MAXN+2];

int dy1[MAXN+2];

int dx2[MAXN+2];

int dy2[MAXN+2];

bool graph[MAXN+2][MAXN+2];

bool on_graph[MAXN+2];

bool calced[MAXN+2];

int f[MAXN+2];

void dijkstra(int s,int d[MAXN+2])

{

     bool visited[MAXN+2];

     memset(visited,0,sizeof(visited));

     memset(d,oo,sizeof(int)*(MAXN+2));

     d[s]=0;

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

     {

         int minu,dminu=oo;

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

             if (!visited[u]&&d[u]<dminu)

                dminu=d[minu=u];

         visited[minu]=true;

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

             if (!visited[u]&&d[u]>dminu+map[minu][u])

                d[u]=dminu+map[minu][u];

     }

}

int dp(int u)

{

    if (calced[u]) return f[u];

    else

    {

        calced[u]=true;

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

            if (graph[u][v])

               f[u]>?=map[u][v]+dp(v);

        return f[u];

    }

}

int main()

{

    scanf(“%d%d%d%d%d%d”,&N,&M,&x1,&y1,&x2,&y2);

    memset(map,oo,sizeof(map));

    for (int i=0,u,v,l;i<M;i++)

        scanf(“%d%d%d”,&u,&v,&l),

        map[u][v]=map[v][u]=l;

    for (int u=1;u<=N;u++) map[u][u]=0;

    dijkstra(x1,dx1);

    dijkstra(y1,dy1);

    dijkstra(x2,dx2);

    dijkstra(y2,dy2);

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

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

            if (u!=v

                &&dx1[u]+map[u][v]+dy1[v]==dx1[y1]

                &&(dx2[u]+map[u][v]+dy2[v]==dx2[y2]

                   ||dy2[u]+map[u][v]+dx2[v]==dx2[y2]))

               on_graph[u]=on_graph[v]=graph[u][v]=true;

    int answer=0;

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

        if (dp(u)>answer) answer=dp(u);

    printf(“%d\n”,answer);

}

 

SDOI2009[Bill的挑战]

动态规划。

f[i][j]表示匹配了前i个字符,匹配的是j中的那些字符串(用二进制压缩)。

动规方程:f[i][j]=sum{f[i-1][j’]}。

边界:f[0][j]=1(j表示的是都被匹配的状态),f[0][j]=0(j表示的是没有都被匹配的状态)。
CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-26

DESCRIPTION:

山东2009年省选 Bill的挑战

*/

#include <stdio.h>

#include <string.h>

 

const int MAXLENGTH=50;

const int MAXN=15;

const int MODER=1000003;

const int MAXALPHABET=128;

typedef char string[MAXLENGTH+1];

int T,N,K;

string s[MAXN];

int f[MAXLENGTH+1][1<<MAXN];

int m[MAXLENGTH][MAXALPHABET];

int NN;

int length;

int main()

{

    scanf(“%d”,&T);

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

    {

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

        for (int i=0;i<N;i++) scanf(“%s”,&s[i]);

        NN=1<<N;

        length=strlen(s[0]);

        memset(f,0,sizeof(f));

        f[0][NN-1]=1;

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

            for (char match=’a’;match<=’z’;match++)

            {

                m[i][match]=0;

                for (int k=0,kk=1;k<N;k++,kk<<=1)

                    if (s[k][i]==’?’||s[k][i]==match)

                       m[i][match]|=kk;

            }

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

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

                if (f[i][j])

                   for (char match=’a’;match<=’z’;match++)

                       f[i+1][j&m[i][match]]=(f[i+1][j&m[i][match]]+f[i][j])%MODER;

        int answer=0;

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

        {

            int c=0;

            for (int j=1;j<NN;j<<=1)

                if (i&j) c++;

            if (c==K) answer=(answer+f[length][i])%MODER;

        }

        printf(“%d\n”,answer);

    }

}

 

SDOI2009[晨跑]

赤裸裸的最小费用流。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-26

DESCRIPTION:

山东2009年省选 晨跑

*/

#include <stdio.h>

#include <string.h>

 

#define oo 0x7f7f7f7f

#define MAXEDGE 1000000

#define MAXV 1000

 

typedef struct struct_edge* edge;

struct struct_edge{int v,c,d;edge n,b;};

struct_edge pool[MAXEDGE];

edge top;

int S,T,V;

edge adj[MAXV];

int q[MAXV];

bool inq[MAXV];

int head,tail;

edge p[MAXV];

int d[MAXV];

void add_edge(int u,int v,int c,int d)

{

     top->v=v;

     top->c=c;

     top->d=d;

     top->n=adj[u];

     adj[u]=top++;

     top->v=u;

     top->c=0;

     top->d=-d;

     top->n=adj[v];

     adj[v]=top++;

     adj[u]->b=adj[v];

     adj[v]->b=adj[u];

}

int min_cost_flow()

{

    int flow=0,cost=0;

    for (;;)

    {

        memset(d,oo,sizeof(d));

        inq[q[head=tail=0]=S]=true;

        d[S]=0;

        p[S]=0;

        while (head<=tail)

        {

              int u;

              inq[u=q[(head++)%MAXV]]=false;

              for (edge i=adj[u];i;i=i->n)

                  if (i->c&&d[i->v]>d[u]+i->d)

                  {

                     if (!inq[i->v])

                        inq[q[(++tail)%MAXV]=i->v]=true;

                     d[i->v]=d[u]+i->d;

                     p[i->v]=i;

                  }

        }

        if (d[T]==oo) break;

        else

        {

            int delta=oo;

            for (edge i=p[T];i;i=p[i->b->v])

                if (delta>i->c) delta=i->c;

            for (edge i=p[T];i;i=p[i->b->v])

                i->c-=delta,i->b->c+=delta;

            flow+=delta;

            cost+=d[T]*delta;

        }

    }

    printf(“%d %d\n”,flow,cost);

}

 

int N,M;

int a,b,c;

int main()

{

    scanf(“%d%d”,&N,&M);

    top=pool;

    S=1,T=N*2,V=N*2;

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

        scanf(“%d%d%d”,&a,&b,&c),add_edge(a+N,b,1,c);

    add_edge(1,1+N,oo,0);

    for (int i=2;i<N;i++) add_edge(i,i+N,1,0);

    add_edge(N,N+N,oo,0);

    min_cost_flow();

}

 

SDOI2009[SuperGCD]

就是求最大公约数,需要用高精度。

然后假设a>=b

gcd(2*a,2*b)=2gcd(a,b)

gcd(2*a+1,2*b+1)=gcd(2*(a-b),2*b+1)

gcd(2*a,b*2+1)=gcd(a,2*b+1)

gcd(2*a+1,b*2)=gcd(2*a+1,b)

gcd(a,0)=a

还有,如果你要交到衡阳八中OJ,为了防止爆栈,请直接写非递归的,否则会像我一样,调试N久。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-26

DESCRIPTION:

山东2009年省选 SuperGCD

*/

#include <stdio.h>

 

#define max(a,b) ((a)>(b)?(a):(b))

const int MAXLENGTH=10000+2;

const int BASE=1000000000;

const int LOG10_BASE=9;

typedef int number[MAXLENGTH/LOG10_BASE+1];

typedef char string[MAXLENGTH];

string A,B;

int AL,BL;

number NA,NB;

int NAL,NBL;

void get_string(string S,int& SL)

{

    char get;

    SL=0;

    while ((get=getchar())!=’\n’) S[SL++]=get;

    S[SL]=0;

}

void get_number(number N,int& NL,string S,int SL)

{

    NL=(SL+LOG10_BASE-1)/LOG10_BASE;

    for (int i=SL-1,j=0;i>=0;i-=LOG10_BASE,j++)

        for (int k=max(i-LOG10_BASE+1,0);k<=i;k++)

            N[j]=N[j]*10+(S[k]-‘0’);

}

void print_number(number N,int NL)

{

    if (!NL) printf(“0”);

    else

    {

        printf(“%d”,N[NL-1]);

        for (int i=NL-2;i>=0;i–)

            printf(“%09d”,N[i]);

    }

}

bool less(number A,int AL,number B,int BL)

{

    if (AL==BL)

    {

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

            if (A[i]!=B[i]) return A[i]<B[i];

        return false;

    }

    else return AL<BL;

}

void dec(number A,int& AL,number B,int& BL)

{

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

        A[i]-=B[i];

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

        if (A[i]<0) A[i+1]–,A[i]+=BASE;

    while (AL>0&&A[AL-1]==0) AL–;

}

void div2(number A,int& AL)

{

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

    {

        if (A[i]%2==1) A[i-1]+=BASE;

        A[i]/=2;

    }

    while (AL>0&&A[AL-1]==0) AL–;

}

void mul2(number A,int& AL)

{

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

        A[i]*=2;

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

        if (A[i]>=BASE)

        {

            A[i]-=BASE;

            if (i+1==AL) A[AL++]=1;

            else A[i+1]+=1;

        }

}

int main()

{

    get_string(A,AL);

    get_string(B,BL);

    get_number(NA,NAL,A,AL),get_number(NB,NBL,B,BL);

    {

        number* A=&NA;

        number* B=&NB;

        int AL=NAL,BL=NBL;

        int mul2_times=0;

        for (;;)

        {

            if (less(*A,AL,*B,BL))

            {

               number* S;

               S=A,A=B,B=S;

               int SL;

               SL=AL,AL=BL,BL=SL;

            }

            if (BL==0) break;   

            if (((*A)[0]%2==1)&&((*B)[0]%2==1)) dec(*A,AL,*B,BL);

            else if (((*A)[0]%2==1)&&((*B)[0]%2==0)) div2(*B,BL);

            else if (((*A)[0]%2==0)&&((*B)[0]%2==1)) div2(*A,AL);

            else div2(*A,AL),div2(*B,BL),mul2_times++;

        }

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

            mul2(*A,AL);

        print_number(*A,AL),printf(“\n”);

    }

}

 

SDOI2009[HH去散步]

动态规划,矩阵优化。

动规方程见注释。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-25

DESCRIPTION:

山东2009年省选 HH去散步

*/

#include <iostream>

#include <string.h>

using namespace std;

 

const int MAXN=20;

const int MAXM=60;

const int MODER=45989;

int N,M,A,B;

long long int t;

int a[MAXM*2],b[MAXM*2];

typedef unsigned int matrix[MAXM*2][MAXM*2];

int K;

matrix mA,mB,mBB,mC;

void mul(matrix A,matrix B,matrix C)

{

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

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

         {

             C[i][j]=0;

             for (int k=0;k<K;k++)

                 C[i][j]=(C[i][j]+A[i][k]*B[k][j])%MODER;

         }

}

void power(matrix A,long long int n,matrix B)

{

     matrix a,b,ab,aa;

     matrix* bp=&b;

     matrix* ap=&a;

     matrix* abp=&ab;

     matrix* aap=&aa;

     matrix* swap;

     memcpy((*ap),A,sizeof(matrix));

     memset((*bp),0,sizeof(matrix));

     for (int i=0;i<K;i++) (*bp)[i][i]=1;

     while (n)

     {

           if (n&1)

           {

              mul(*bp,*ap,*abp);

              swap=bp;

              bp=abp;

              abp=swap;

           }

           mul(*ap,*ap,*aap);

           swap=ap;

           ap=aap;

           aap=swap;

           n>>=1;

     }

     memcpy(B,*bp,sizeof(matrix));

}

int main()

{

    cin>>N>>M>>t>>A>>B;

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

        cin>>a[i]>>b[i],

        a[i+M]=b[i],b[i+M]=a[i];

    //f[T][EDGE]表示走了T,在最后走的是EDGE的方案数

    //f[1][EDGE]=1 v(EDGE)=A

    //f[T][EDGE]=sum{f[T-1][EDGE’];v(EDGE)=u(EDGE’) and EDGE!=EDGE’的反向边}

    K=M*2;

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

        if (a[i]==A) mA[0][i]=1;

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

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

            if (b[i]==a[j]&&i!=j+M&&j!=i+M)

               mB[i][j]=1;

    power(mB,t-1,mBB);

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

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

            for (int k=0;k<K;k++)

                mC[i][j]=(mC[i][j]+mA[i][k]*mBB[k][j])%MODER;

    int answer=0;

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

        if (b[i]==B) answer=(answer+mC[0][i])%MODER;

    cout<<answer<<endl;

}

 

SDOI2008[递归数列(版本II)]

矩阵加速求数列前n项和。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-25

DESCRIPTION:

山东2008年省选 递归数列(版本II)

*/

#include <iostream>

#include <string.h>

using namespace std;

 

const int LOG2_MAXN=60;

const int MAXK=15;

typedef long long int matrix[MAXK][MAXK];

int k;

matrix A,B;

long long int m,n;

int p;

void mul(matrix A,matrix B,matrix C)

{

     memset(C,0,sizeof(matrix));

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

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

             for (int K=0;K<k;K++)

                 C[i][j]=(C[i][j]+A[i][K]*B[K][j])%p;

}

void mul(int a,int b,int c,matrix A,matrix B,matrix C)

{

     memset(C,0,sizeof(matrix));

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

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

             for (int k=0;k<c;k++)

                 C[i][j]=(C[i][j]+A[i][k]*B[k][j])%p;

}

void power(long long int n,matrix A)

{

     static bool calced;

     static matrix T[LOG2_MAXN];

     if (!calced)

     {

        calced=true;

        memcpy(T[0],B,sizeof(matrix));

        for (int i=1;i<LOG2_MAXN;i++) mul(T[i-1],T[i-1],T[i]);

     }

     memset(A,0,sizeof(matrix));

     for (int i=0;i<k;i++) A[i][i]=1;

     int t=0;

     while (n!=0)

     {

           if (n%2)

           {

              matrix AT;

              mul(A,T[t],AT);

              memcpy(A,AT,sizeof(matrix));

           }

           t++;

           n/=2;

     }

}

void get(matrix S,long long int n)

{

     if (n==0) memset(S,0,sizeof(matrix));

     else if (n%2==0)

     {

          matrix a,b;

          get(a,n>>1);

          power(n>>1,b);

          for (int i=0;i<k;i++) b[i][i]=(b[i][i]+1)%p;

          mul(a,b,S);

     }

     else

     {

          matrix a,b;

          get(a,n-1);

          power(n-1,b);

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

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

                  S[i][j]=(a[i][j]+b[i][j])%p;

     }

}

int main()

{

    cin>>k;

    for (int i=0;i<k;i++) cin>>A[0][i];

    for (int i=0;i<k;i++) cin>>B[k-i-1][k-1];

    for (int i=1;i<k;i++) B[i][i-1]=1;

    cin>>m>>n>>p;

    matrix S;

    matrix AXS;

    get(S,m-1);

    mul(1,k,k,A,S,AXS);

    int a=AXS[0][0];

    get(S,n);

    mul(1,k,k,A,S,AXS);

    int b=AXS[0][0];

    cout<<((b-a)%p+p)%p<<endl;

}

 

SDOI2010[所驼门王的宝藏]

强连通缩点,然后动态规划。


CODE:


/*


AUTHOR: Su Jiao


DATE: 2010-7-25


DESCRIPTION:


山东2010年省选 所驼门王的宝藏


*/


#include <stdio.h>


 


const int MAXN=100000+2;


const int NEXT=8;


const int MAXE=1000000;


const int MAXV=200000+2;


const int dx[NEXT]={-1,-1,-1, 0, 0, 1, 1, 1};


const int dy[NEXT]={-1, 0, 1,-1, 1,-1, 0, 1};


struct Door{int x,y,type,id;};


typedef struct struct_edge* edge;


struct struct_edge{int v;edge n;};


int N,R,C;


Door door[MAXN];


struct_edge pool[MAXE];


edge top=pool;


edge adj[MAXV];


int time_stamp;


int LOW[MAXN];


int DFN[MAXN];


int stack_top;


int stack[MAXN];


bool instack[MAXN];


int p[MAXN];


int size[MAXN];


int f[MAXN];


bool less_X(Door a,Door b)


{


     return a.x<b.x;


}


bool less_Y(Door a,Door b)


{


     return a.y<b.y;


}


bool less_X_Y(Door a,Door b)


{


     if (a.x==b.x) return a.y<b.y;


     else return a.x<b.x;


}


bool equal(Door a,Door b)


{


     return a.x==b.x&&a.y==b.y;


}


void quick_sort(bool (*less)(Door,Door),int L,int R)


{


     int i=L,j=R;


     Door mid=door[(L+R)>>1],swap;


     while (i<=j)


     {


           while (less(door[i],mid)) i++;


           while (less(mid,door[j])) j–;


           if (i<=j)


           {


              swap=door[i],door[i]=door[j],door[j]=swap;


              i++,j–;


           }


     }


     if (L<j) quick_sort(less,L,j);


     if (i<R) quick_sort(less,i,R);


}


int binary_search(bool (*less)(Door,Door),int L,int R,Door key)


{


    R++;


    while (L+1!=R)


    {


        int mid=(L+R)>>1;


        if (!less(key,door[mid])) L=mid;


        else R=mid;


    }


    return L;


}


void add_edge(int u,int v)


{


     top->v=v,top->n=adj[u],adj[u]=top++;


}


void build_graph()


{


     quick_sort(less_X,1,N);


     for (int u=1,v;u<=N;u=v)


     {


         int p=0;


         for (v=u;door[u].x==door[v].x&&!p;v++)


             if (door[v].type==1) p=door[v].id;


         if (!p) continue;


         for (v=u;door[u].x==door[v].x;v++)


             add_edge(p,door[v].id);


         for (v=u;door[u].x==door[v].x;v++)


             if (door[v].type==1) adj[door[v].id]=adj[p];


     }


     quick_sort(less_Y,1,N);


     for (int u=1,v;u<=N;u=v)


     {


         int p=0;


         for (v=u;door[u].y==door[v].y&&!p;v++)


             if (door[v].type==2) p=door[v].id;


         if (!p) continue;


         for (v=u;door[u].y==door[v].y;v++)


             add_edge(p,door[v].id);


         for (v=u;door[u].y==door[v].y;v++)


             if (door[v].type==2) adj[door[v].id]=adj[p];


     }


     quick_sort(less_X_Y,1,N);


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


         if (door[u].type==3)


         {


            Door key;


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


            {


                key.x=door[u].x+dx[i];


                key.y=door[u].y+dy[i];


                int v=binary_search(less_X_Y,1,N,key);


                if (equal(door[v],key)) add_edge(door[u].id,door[v].id);


            }


         }


}


void tarjan(int u)


{


     instack[stack[++stack_top]=u]=true;


     DFN[u]=LOW[u]=++time_stamp;


     for (edge i=adj[u];i;i=i->n)


         if (!DFN[i->v])


         {


            tarjan(i->v);


            LOW[u]=LOW[i->v]<LOW[u]?LOW[i->v]:LOW[u];


         }


         else if (instack[i->v]) LOW[u]=DFN[i->v]<LOW[u]?DFN[i->v]:LOW[u];


     if (DFN[u]==LOW[u])


     {


        do


        {


          int st=stack[stack_top];


          add_edge(u+N,st);


          size[p[st]=u]++;


          instack[st]=false;


        }


        while (stack[stack_top–]!=u);


     }


}


int dp(int u)


{


    if (f[u]) return f[u];


    else


    {


        for (edge j=adj[u+N];j;j=j->n)


            for (edge i=adj[j->v];i;i=i->n)


                if (p[i->v]!=u)


                   f[u]>?=dp(p[i->v]);


        f[u]+=size[u];


        return f[u];


    }


}


int main()


{


    scanf(“%d%d%d”,&N,&R,&C);


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


        scanf(“%d%d%d”,&door[i].x,&door[i].y,&door[i].type),door[i].id=i;


    build_graph();


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


        if (!DFN[u]) tarjan(u);


    int answer=0;


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


        if (dp(p[u])>answer)


           answer=dp(p[u]);


    printf(“%d\n”,answer);


}


 

SDOI2010[外星千足虫]

赤裸裸的高斯消元,但是是O(n^2*m)的,犹豫了一下,然后百度一下,发现要用位运算来压缩。

CODE:

/*

AUTHOR: Su Jiao

DATE: 2010-7-24

DESCRIPTION:

山东2010年省选 外星千足虫

*/

#include <stdio.h>

 

typedef unsigned int bit;

const int MAXN=1000;

const int MAXM=2000;

const bit mod32=(1<<5)-1;

const bit div32=5;

int N,M;

bit _matrix[MAXM][((MAXN+1)>>5)+1];

bit* matrix[MAXM];

bit answer[((MAXN+1)>>5)+1];

int main()

{

    #define assign(i,j,value) (matrix[i][(j)>>div32]|=(value)<<((j)&mod32))

    #define get(i,j) ((matrix[i][(j)>>div32]>>((j)&mod32))&1)

    #define get_answer(j) ((answer[(j)>>div32]>>((j)&mod32))&1)

    #define swap(a,b) {bit* s=matrix[a];matrix[a]=matrix[b];matrix[b]=s;}

    scanf(“%d%d”,&N,&M);

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

    {

        matrix[i]=_matrix[i];

        getchar();

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

            assign(i,j,getchar()==’1′);

        getchar();

        assign(i,N,getchar()==’1′);

    }

    bool have_solution=false;

    for (int i=0,step=0;i<M;i++)

    {

        if (get(i,step))

        {

           swap(step,i);

           go:

           for (int j=step+1;j<M;j++)

               if (get(j,step))

                  for (int k=(step>>div32);k<=(N>>div32);k++)

                      matrix[j][k]^=matrix[step][k];

           step++;

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

               if (get(j,step))

               {

                  swap(j,step);

                  goto go;

               }

           if (step==N)

           {

              printf(“%d\n”,i+1);

              for (;step–;)

              {

                  for (int k=step+1;k<N;k++)

                      answer[step>>div32]^=(get_answer(k)&get(step,k))<<(step&mod32);

                  answer[step>>div32]^=get(step,N)<<(step&mod32);

              }

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

                  printf(“%s\n”,get_answer(j)?“?y7M#”:“Earth”);

              have_solution=true;

              break;

           }

        }

    }

    if (!have_solution) printf(“Cannot Determine\n”);

}

 

RQNOJ418[浪浪的小爱好]

动态规划,动规方程:f[i]=min{f[j]+cost(j,i)},cost(j,i)=m+sqr(s[i]-s[j]),s[i]表示从1到i这些音节的距离和。


然后朴素的一定TLE,所以斜率优化,见这里


CODE:


/*


AUTHOR: Su Jiao


DATE: 2010-7-24


DESCRIPTION:


动态规划 专练


http://www.rqnoj.cn/Problem_418.html


*/


#include <stdio.h>


 


const int oo=(~0u)>>1;


const int MAXN=200000;


int n,m;


char a[MAXN+2];


char b[MAXN+2];


long long int s[MAXN+2];


long long int f[MAXN+2];


int q[MAXN+2];


int head,tail;


int main()


{


    //f[i]=min{f[j]+cost(j,i)}


    //cost(j,i)=m+sqr(s[i]-s[j])


    scanf(“%d%d”,&n,&m);


    scanf(“%s%s”,&a,&b);


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


        s[i+1]=s[i]+(a[i]>=b[i]?a[i]-b[i]:b[i]-a[i]);


    #define value(j) f[j]+(s[i]-s[j])*(s[i]-s[j])+m


    #define ky(k,j) (f[k]-f[j]+s[k]*s[k]-s[j]*s[j])


    #define kx(k,j) (s[k]-s[j])


    q[head=tail=0]=0;


    f[0]=-m;


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


    {


        while (head<tail&&value(q[head])>=value(q[head+1])) head++;


        int j=q[head];


        f[i]=value(j);


        while (head<tail&&(s[q[tail]]==s[i]||ky(q[tail-1],q[tail])*kx(q[tail],i)>=ky(q[tail],i)*kx(q[tail-1],q[tail]))) tail–;


        q[++tail]=i;


    }


    printf(“%d\n”,int(f[n]));


}


 

RQNOJ225[书本整理]

动态规划,这次还自己写了个快排。


f[i][j]表示前i本中已经选了j本,并且最后一本选的是i时的最优值。


动规方程:f[i][j]=min{f[k][j-1]+abs(book[i].width-book[k].width);k<i}。


边界:f[i][0]=0,f[i][i]=sum{abs(book[j].width-book[j+1].width);j<i},f[i][j]=oo(j>i)。


最后的答案:min{f[i][n-k]}


CODE:


/*


AUTHOR: Su Jiao


DATE: 2010-7-24


DESCRIPTION:


动态规划 专练


http://www.rqnoj.cn/Problem_225.html


[JSOI2007]书本整理


*/


#include <stdio.h>


#include <stdlib.h>


 


const int oo=(~0u)>>2;


const int MAXN=100;


struct Book{int h,w;};


int n,k;


Book book[MAXN+2];


int f[MAXN+2][MAXN+2];


void quick_sort(int L,int R)


{


     int i=L,j=R;


     Book mid=book[(L+R)>>1],swap;


     while (i<=j)


     {


           while (book[i].h<mid.h) i++;


           while (book[j].h>mid.h) j–;


           if (i<=j)


              swap=book[i],book[i]=book[j],book[j]=swap,


              i++,j–;


     }


     if (L<j) quick_sort(L,j);


     if (i<R) quick_sort(i,R);


}


int main()


{


    scanf(“%d%d”,&n,&k);


    for (int i=1;i<=n;i++) scanf(“%d%d”,&book[i].h,&book[i].w);


    quick_sort(1,n);


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


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


            f[i][j]=oo;


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


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


        {


            if (j==0) f[i][j]=0;


            else if (j==i) f[i][j]=i>1?f[i-1][j-1]+abs(book[i].w-book[i-1].w):0;


            else for (int ii=1,jj=j-1;ii<i;ii++)


                     f[i][j]<?=f[ii][jj]+(jj?abs(book[i].w-book[ii].w):0);


        }


    int answer=oo;


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


        if (answer>f[i][n-k]) answer=f[i][n-k];


    printf(“%d\n”,answer);


}