Noip2014day1解题报告
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noip2014day1解题报告相关的知识,希望对你有一定的参考价值。
Noip2014day1解题报告
张炳琪
一.时间分配
T1:20分钟
T2:60分钟
T3:130分钟
二.答题情况和错因
T1:100 T2:100 T3:75 TOT 275
T1:一个比较简单的模拟题,用常量数组会看起来不那么乱
T2:刚开始考虑dp后来发现在dfs第二次的时候并不需要dp所以遍历一遍输出就能得到答案了
T3:dp的转移方法不对会超时,背包转移写的不对不敢写
三.题目解析
T1:常量数组表示胜负,其余的就是循环模拟了
T2:应该是类似于树形dp的一个题目先转有根树,维护孩子最大值和孩子的权值总和
dfsdp分为两种情况,第一种是和孙子形成有序数对,这时候就用上刚才维护的东西了 相乘即可
另一种是儿子和儿子形成有序数对 这个我想不到什么好办法,只能求个前缀和啥的乱搞 不过理论复杂度依旧是O(n)的,不过常数略大
注意所有的计算都是单向的,所以说最后要乘以二
T3:一个以前做过的背包问题,忘记背包具体怎么写了 就乱搞一下吧
dp[i][j] 表示到了第i个位置高度为j的最小步数,tal[i]表示改点点击的话上飞的高度
down[i]表示不点击的话下降的高度 然后考虑向dp[i + 1][x]转移可以考虑的是上升的话次数无限,则枚举点击的次数 向dp[i + 1][j + tal[i] * 点击次数]转移下降的话不需要点击 向dp[i + 1][j - down[i]]转移 考虑一下有柱子的地方不转移 转移飞到上界之外的情况
正解是背包,原理是利用完全背包的那个dp方式,减少时间复杂度
四.代码
T1:
#include<cstdio> #include<algorithm> #include<iostream> #define MAXN 2010 using namespace std; const int mp[5][5] = { 0,1,2,2,1, 2,0,1,2,1, 1,2,0,1,2, 1,1,2,0,2, 2,2,1,1,0 }; int notea[MAXN];int noteb[MAXN]; int ansa = 0,ansb = 0; int n,na,nb,cnta,cntb; int main() { //freopen("rps.in","r",stdin);freopen("rps.out","w",stdout); scanf("%d%d%d",&n,&na,&nb); for(int i = 1;i <= na;i++)scanf("%d",¬ea[i]); for(int i = 1;i <= nb;i++)scanf("%d",¬eb[i]); cnta = 1;cntb = 1; for(int i = 1;i <= n;i++) { int op = mp[notea[cnta]][noteb[cntb]]; if(op == 1)ansb++; if(op == 2)ansa++; cnta++;cntb++; if(cnta == na + 1)cnta = 1; if(cntb == nb + 1)cntb = 1; } printf("%d %d",ansa,ansb); return 0; }
T2:
#include<cstdio> #include<algorithm> #include<iostream> #define MAXN 200100 const int mod = 10007; using namespace std; struct Edge { int vi; int vj; int next; } edge[MAXN << 1]; int wei[MAXN];//点权 int sum_[MAXN]; //儿子和 int maxx[MAXN];//最大儿子 int stack[MAXN],top;//递归内储存儿子的 int head[MAXN],now = 0; int SUM[MAXN];//递归内前缀和 int note[MAXN];//最后答案 int n,ans = 0; void push(int vi,int vj) { now++; edge[now].vi = vi; edge[now].vj = vj; edge[now].next = head[vi]; head[vi] = now; } int read() { int num = 0; char c = getchar(); while(c > ‘9‘ || c < ‘0‘)c = getchar(); while(c >= ‘0‘ && c <= ‘9‘) { num *= 10; num += c - ‘0‘; c = getchar(); } return num; } void dfs(int noww,int fa) { for(int i = head[noww];i;i = edge[i].next) { int vj = edge[i].vj; if(vj == fa)continue; sum_[noww] += wei[vj]; maxx[noww] = max(maxx[noww],wei[vj]); dfs(vj,noww); } sum_[noww] %= mod; } void dp(int noww,int fa) { for(int i = head[noww];i;i = edge[i].next)//和孙子配对 { int vj = edge[i].vj; if(vj == fa)continue; note[noww] += sum_[vj] * wei[noww]; note[noww] %= mod; ans = max(ans,maxx[vj] * wei[noww]); dp(vj,noww); } top = 0; // 重置计数器 int op = 0;//寻找次大 bool flag = false; for(int i = head[noww];i;i = edge[i].next) { int vj = edge[i].vj; if(vj == fa)continue; if(wei[vj] >= op) { if(flag)op = wei[vj]; else if(wei[vj] == maxx[noww]) { flag = true; } else op = wei[vj]; } stack[++top] = wei[vj]; SUM[top] = SUM[top- 1] + wei[vj]; SUM[top] %= mod; } ans = max(ans,op * maxx[noww]); for(int i = top;i > 1;i--) { note[noww] += stack[i] * SUM[i - 1]; note[noww] %= mod; } } int main() { //freopen("link.in","r",stdin);freopen("link.out","w",stdout); n = read(); for(int i = 1;i < n;i++) { int vi = read(),vj = read(); push(vi,vj); push(vj,vi); } for(int i = 1;i <= n;i++) wei[i] = read(); dfs(1,0); dp(1,0); int op = 0; for(int i = 1;i <= n;i++) { op += note[i]; if(op >= mod)op -= mod; } op = op * 2 % mod; printf("%d %d",ans,op); return 0; }
T3:
#include<cstdio> #include<cstring> #define MAXN 10010 using namespace std; int dp[MAXN][1010]; int tal[MAXN]; int don[MAXN]; bool zhu[MAXN];int up[MAXN];int low[MAXN];//储存柱子的数据 int tot = 0; int n,m,k; int read() { int nm = 0; char c = getchar(); while(c > ‘9‘ || c < ‘0‘)c = getchar(); while(c <= ‘9‘ && c >= ‘0‘) { nm *= 10; nm += c - ‘0‘; c = getchar(); } return nm; } int min(int x,int y) { return x < y ? x : y; } int max(int x,int y) { return x > y ? x : y; } void debug(int x) { for(int i = 1;i <= m;i++) { int op = dp[x][i]; if(op == 1044266558)op = 1000; printf("%d ",op); } printf("\n"); } int main() { //freopen("bird.in","r",stdin);freopen("bird.out","w",stdout); memset(dp,0x3e,sizeof(dp)); n = read();m = read();k = read(); for(int i = 0;i < n;i++) { tal[i] = read(); don[i] = read(); } for(int i = 1;i <= m;i++) dp[0][i] = 0; for(int i = 1;i <= k;i++) { int op = read(); zhu[op] = true; low[op] = read(); up[op] = read(); } for(int i = 0;i <= n;i++) { if(!zhu[i])up[i] = m + 1; } for(int i = 0;i <= n;i++) { bool flag = false; for(int j = low[i] + 1;j <= up[i] - 1;j++) { if(dp[i][j] == 1044266558)continue; flag = true; int zz; if(low[i + 1] > j) zz = (low[i + 1] - j) / tal[i]; else zz = 1; int op = j + tal[i] * zz; while(op < up[i + 1]) // 这里刚开始写错了 { if(op > low[i + 1]) { //dp[i + 1][op] = min(dp[i + 1][op],dp[i][j] + zz); if(dp[i + 1][op] > dp[i][j] + zz) dp[i + 1][op] = dp[i][j] + zz; else break; } op += tal[i]; zz++; } if(!zhu[i + 1] && op > m)dp[i + 1][m] = min(dp[i + 1][m],dp[i][j] + zz); op = j - don[i]; if(op > low[i + 1] && op < up[i + 1])// dp[i + 1][op] = min(dp[i][j],dp[i + 1][op]); } if(!flag) { printf("0\n%d",tot); return 0; } if(zhu[i])tot++; //debug(i + 1); } int cns = 0x7fffffff; for(int i = 1;i <= m;i++) { cns = min(cns,dp[n][i]); } printf("1\n%d",cns); return 0; }
以上是关于Noip2014day1解题报告的主要内容,如果未能解决你的问题,请参考以下文章