武汉大学校赛总结 + E题+F题

来源:互联网 发布:javascript 英文地图 编辑:程序博客网 时间:2024/06/02 20:21

E.Your NP has been charged full

这次比赛好难看,除了抢了一个签到题的一血,又是跟去年差不多的难看。
感觉主要还是练的不够多,一个一眼dp题没有看出来,还有一个找规律题找了一整场,从开局2分钟抢一血到出第二个题隔了200分钟(Galigaygay)
总结起来就是:还是不够熟练啊!!!
E题
题意是一个游戏有n个回合,每次给出一组数,每组数里面有3个数字,ai,bi,ci我们每次可以从每组数里选出一个作为buff 此回合获得的成就值是(1+∑ai)(1 + ∑bi) (1 + ∑ci),但是每个buff只能保留三个回合,求最后获得的最大成就值是多少。

其实由于每个buff只能保留两个回合,我们只要记前两行的状态就行了,dp[i][j][k][l]表示第i个回合选了l buff,第i-1个回合选了k buff ,第i-2回合选j buff的最大值。然后就跟着状态随便推推就能得到转移方程了。

#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<set>#include<map>#include<time.h>#include<cstdio>#include<vector>#include<list>#include<stack>#include<queue>#include<iostream>using namespace std;#define  LONG long longconst int   INF=0x3f3f3f3f;const LONG  MOD=1e9+ 7;const double PI=acos(-1.0);#define clrI(x) memset(x,-1,sizeof(x))#define clr0(x) memset(x,0,sizeof x)#define clr1(x) memset(x,INF,sizeof x)#define clr2(x) memset(x,-INF,sizeof x)#define EPS 1e-10#define lson  l , mid , rt<< 1#define rson  mid + 1 ,r , (rt<<1)+1#define root 1, m , 1double dp[10010][4][4][4] ;double num[10010][5] ;int main(){    int n ;    int sta = clock() ;    while(cin>> n)    {        clr0(dp) ;        for(int i = 1 ; i <= n ;++ i)            for(int j = 1; j <= 3 ;++ j)                scanf("%lf",&num[i][j]) ;        dp[1][1][1][1] = 1 + num[1][1] ;        dp[1][1][1][2] = 1 + num[1][2] ;        dp[1][1][1][3] = 1 + num[1][3] ;        for(int i = 1; i <=3 ;++i)            for(int j = 1; j <= 3 ;++ j)                if(i == j)                dp[2][1][i][j] = max(dp[2][1][i][j] , dp[1][1][1][i] +  (1 + num[1][i] + num[2][j]) ) ;                else                dp[2][1][i][j] = max(dp[2][1][i][j] , dp[1][1][1][i] + (1 + num[1][i]) * (1 + num[2][j]) ) ;        for( int x = 3 ; x <= n ;++ x )        for(int i = 1; i <= 3 ;++i)            for(int j =1; j <= 3 ; ++j)                for(int k =1; k <=3 ;++ k)                    for(int l =1; l <= 3 ;++ l)                    if(i == j && j == k)                    dp[x][i][j][k] = max(dp[x][i][j][k] , dp[x - 1][l][i][j] + ( 1 + num[x- 2][i] + num[x - 1][j] + num[x][k] )  ) ;                    else if( i == j)                    dp[x][i][j][k] = max(dp[x][i][j][k] , dp[x - 1][l][i][j] + ( 1 + num[x- 2][i] + num[x - 1][j] ) * (1 + num[x][k] )  ) ;                    else if( j == k)                    dp[x][i][j][k] = max(dp[x][i][j][k] , dp[x - 1][l][i][j]  + ( 1 + num[x - 2][i] ) * (1 + num[x - 1][j] + num[x][k] )  ) ;                    else if(i == k)                    dp[x][i][j][k] = max(dp[x][i][j][k] , dp[x - 1][l][i][j]  + ( 1 + num[x - 2][i] + num[x ][k] ) * ( 1 + num[x - 1][j] )  ) ;                    else                    dp[x][i][j][k] = max(dp[x][i][j][k] , dp[x - 1][l][i][j]  + ( 1 + num[x- 2][i] )* (1 + num[x - 1][j] ) * (1 + num[x][k] )  ) ;    double ans =  0 ;    for(int i = 1; i <=3 ;++i)        for(int j =1 ; j <= 3 ; ++ j)            for(int k = 1; k <= 3 ;++ k)                ans = max(ans , dp[n][i][j][k]);    printf("%.7lf\n",ans);    }}

F题

题意是给一棵树,每个节点有点权,初始点权是0,然后有K次操作,每次操作都是把从u点到v点这条路径上的点的权值加上一个数字,最后找出所有点中,权值最大的点。
树链剖分裸题,但是点和操作都有50万,因此毫无人性的卡了log,实际上这应该是一道树上dp题
类似于poj3417
我们可以先离线求一下所有操作的LCA,然后每次操作的点u,v加上这个数值,同时把lca(u,v)和father[lca(u,v)]减去这个数,这样dfs一次之后,每个点被加的数字都会被统计到dp[u]里进去,这样总的复杂度就是O(N+K)了

#include<cmath>#include<algorithm>#include<cstring>#include<string>#include<set>#include<map>#include<time.h>#include<cstdio>#include<vector>#include<list>#include<stack>#include<queue>#include<iostream>using namespace std;#define  LONG long longconst int   INF=0x3f3f3f3f;const LONG  MOD=1e9+ 7;const double PI=acos(-1.0);#define clrI(x) memset(x,-1,sizeof(x))#define clr0(x) memset(x,0,sizeof x)#define clr1(x) memset(x,INF,sizeof x)#define clr2(x) memset(x,-INF,sizeof x)#define EPS 1e-10#define lson  l , mid , rt<< 1#define rson  mid + 1 ,r , (rt<<1)+1#define root 1, m , 1struct Edge{    int to , next ;}edge[1100000];int head[510000] ;struct Query{    int to , next , id ;}query[1200000];int Qhead[1100000] ;int tot , tt ;LONG  dp[1200000] ;void Add_Edge(int u ,int v ){    edge[++tot].to = v ;    edge[tot].next = head[u] ;    head[u] = tot ;}void Add_Q(int u , int v , int id ){    query[++tt].to = v;    query[tt].id = id ;    query[tt].next = Qhead[u] ;    Qhead[u] = tt ;}int vis[550000] ;int take[550000] ;int fa[550000] ;int Fa[550000] ;LONG val[550000] ;void Init(){    clr0( dp ) ;    clrI(head) ;    clrI(Qhead) ;    tot = 0 ;    tt = 0 ;    clr0(val) ;    clr0(vis) ;    clrI(fa) ;    clr0(take) ;}int Find(int x){    if(fa[x] ==  -1) return x;    return fa[x] == x ? x : fa[x] = Find(fa[x]) ;}void dfs1(int pre , int u){    Fa[u] = pre ;    for(int i = head[u] ; i != -1 ; i = edge[i].next)    {        int v = edge[i].to ;        if(v == pre) continue ;        dfs1(u , v) ;    }}void dfs( int u){    vis[u] = 1;    for(int i = head[u]; i != -1 ; i = edge[i].next)    {        int v = edge[i].to ;        if(vis[v] ) continue  ;        dfs(v) ;        fa[v] = u ;        dp[u] += dp[v] ;    }    for(int i = Qhead[u] ; i != -1 ; i= query[i].next)    {        int v = query[i].to ;        dp[u] += val[query[i].id ]  ;        if( vis[v] )        {            if(!take[query[i].id])            {                dp[Find(v)] -= val[query[i].id] ;                take[query[i].id] = 1;                dp[Fa[Find(v)]] -= val [query[i].id] ;            }        }    }}int main(){    Init() ;    int n , m ;    cin>> n >> m ;    int  u , v ;    for(int i =1; i < n ; ++ i)    {        scanf("%d%d" , & u, & v) ;        Add_Edge(u , v) ;        Add_Edge(v,  u) ;    }    LONG  w ;    dfs1(-1 , 1 );    for(int i =  1; i <= m ;++ i )    {        scanf("%d%d%lld",&u,&v, &w) ;        val[i] = w;        Add_Q(u , v , i ) ;        Add_Q(v , u , i ) ;    }    dfs(1) ;    int x = 1;    for(int i = 1 ; i <= n ;++ i)    {//        printf("%lld ",dp[i]);        if(dp[i] > dp[x])        {            x = i ;        }    }//    cout<<endl;    printf("%d %lld\n",x,dp[x]) ;}
1 0
原创粉丝点击