武汉大学校赛总结 + 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
- 武汉大学校赛总结 + E题+F题
- 2017武汉大学校赛网络预选赛e题
- 武汉大学校赛(个人总结+补题)
- 2017武汉大学校赛网络预选赛b题
- 2017武汉大学校赛网络预选赛g题
- 2017武汉大学校赛网络预选赛d题
- 2017武汉大学校赛 网络预选赛 简单题题解
- 2017武汉大学校赛网络预选赛c题
- 2017浙江理工大学校赛E题
- 2012中南大学校赛F题 - 旋转卡壳的思维...
- 积木积水(广东工业大学校赛决赛2016E题)
- 2016年武汉科技大学邀请赛网络赛 F题
- 2016武汉科技大学邀请赛现场赛 F题
- 2016年武汉科技大学邀请赛网络赛 E题
- 2016武汉科技大学邀请赛现场赛 E题
- 2012山东大学校赛,高年级组【Problem F 一字棋 】
- 2017河南工业大学校赛 F Hmz 的女装
- 2017华中地区邀请赛暨武汉大学校赛现场赛小结
- 1018. 锤子剪刀布
- Kafka的Topic操作
- 返回上一页并强制刷新的js代码
- java 从键盘输入数据判断是否是整数,是的话再求和
- 面试8之给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成
- 武汉大学校赛总结 + E题+F题
- Linux-进程描述(2)之进程标识符进程位置与环境变量
- 静态与非静态
- 选举游戏(京东2016实习生真题)
- [学习笔记06]string总结
- 如何删除GitHub上资源库中的项目
- 保存Hive查询的方法
- c之柔性数组成员
- ZOJ1032-Area 2(已知点坐标求多边形面积,求线段上的整点数量,pick定理)