Noip2015day2解题报告
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Noip2015day2解题报告相关的知识,希望对你有一定的参考价值。
解题报告
张炳琪
一:时间分配
T1:30分钟
T2:2小时
T3:40分钟打暴力
二:答题情况及错因
T1;100 T2:90 T3:60 Tot:250
T1:听老师讲过很多遍
T2:推了五十多分钟吧,这几天做dp做得还是有点头绪的,错的十分是需要压维,不然空间会炸
T3:特判的两种情况打的暴力
三:题目解析
T1:
二分答案 然后On验证每个答案
可行性证明 首先决策具有单调性 若当前最大距离可行那么这个最大距离减小后依旧可行然后 我们是可以On来判定答案是否合法的 我们跳到第一个超出该范围的石头上,而不超出这个范围的都需要移走
T2:
首先猜测
dp[i][j][k]第一串匹配到第i位 第二串匹配到第j位 用了k个串的方案数然后考虑第i位的匹配情况如果这一位可以和 枚举的地j位匹配的话 就进行转移如果不能的话 就是0
dp[i][j][k] += dp[1 ~ i - 1][j - 1][k - 1] 意为新开一个串 储存当前匹配的这个值这里的多次求和可以使用前缀和优化
dp[i][j][k] += dp[i - 1][j - 1][k] 意为承接上一次的那个串进行匹配
最后统计所有的dp[i][m][k]
T3:
应用算法 倍增求lca 树上前缀和
首先 预处理每两个点的lca, 路径长度 然后二分一下答案 对于答案进行可行性判断
枚举一下所有路线 找出所有长度比答案大的路径,用树上前缀和求出他们路径的交 ,然后找出交里面权值最大的一条路
将其变为虫洞 (判断是否可行)
T1:
#include<cstdio> #include<algorithm> #include<cstring> #define MAXN 500501 using namespace std; int L,n,m; int note[MAXN]; bool check(int x) { int tot = 0; int last = 0; for(int i = 1; i <= m; i++) { int op = note[i] - note[last]; if(op >= x)last = i; else tot++; } return tot <= n; } int main() { //freopen("stone.in","r",stdin);freopen("stone.out","w",stdout); scanf("%d%d%d",&L,&m,&n); for(int i = 1; i <= m; i++) scanf("%d",¬e[i]); m++; note[m] = L; int l = 1,r = L; while(l + 1 < r) { int mid = (l + r) >> 1; if(check(mid)) l = mid; else r = mid; } printf("%d",check(r)?r:l); return 0; }
T2:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 101 #define mod 1000000007 using namespace std; long long dp[MAXN * 10][2][MAXN * 2];//应该是要压一维的 算了 char s1[MAXN * 10]; char s2[MAXN * 10]; int n,m,kk; int main() { //freopen("substring.in","r",stdin);freopen("substring.out","w",stdout); scanf("%d%d%d",&n,&m,&kk); scanf("%s%s",s1 + 1,s2 + 1); long long ans = 0; for(int i = 1; i <= n; i++) if(s1[i] == s2[1])dp[i][1][1] = 1; // 代表从这个点可以开始扩展匹配 for(int j = 0,p = 2; p <= m; j ^= 1,p++) { for(int k = 1; k <= kk ; k++) { long long cnt = 0; // 前缀和优化 for(int i = 1; i <= n; i++) { cnt += dp[i - 1][j ^ 1][k - 1]; cnt %= mod; if(s1[i] == s2[p]) { dp[i][j][k] = cnt + dp[i - 1][j ^ 1][k]; dp[i][j][k] %= mod; } else dp[i][j][k] = 0;//如果压维的话这个必须要有 因为是循环利用 } } } for(int i = 1; i <= n; i++)ans = (ans + dp[i][m & 1][kk]) % mod; cout << ans; return 0; }
T3:
#include<cstdio> #include<cstring> #include<algorithm> #define MAXN 300300 using namespace std; struct Edge{ int vi; int vj; int wei; int next; }edge[MAXN << 1]; int head[MAXN]; int deep[MAXN]; int lca[MAXN]; int cos[MAXN]; int be[MAXN]; int ed[MAXN]; int cost[MAXN]; int maxx = 0; int n,m,now,ans,top; int fa[MAXN][20]; int qianzhui[MAXN]; int tmp; 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 push(int vi,int vj,int wei) { now++; edge[now].vi = vi; edge[now].vj = vj; edge[now].wei = wei; edge[now].next = head[vi]; head[vi] = now; } void dfs(int noww,int father) { for(int i = head[noww];i;i = edge[i].next) { int vj = edge[i].vj; if(vj == father)continue; fa[vj][0] = noww; cos[vj] = cos[noww] + edge[i].wei; deep[vj] = deep[noww] + 1; dfs(vj,noww); } } int query_lca(int x,int y) { if(deep[x] < deep[y])swap(x,y); int depst = deep[x] - deep[y]; int cnt = 0; while(depst) { if(depst & 1)x = fa[x][cnt]; cnt++; depst >>= 1; } if(x == y)return x; for(int i = 19;i >= 0;i--) { if(fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; } void dfs2(int noww,int father) { for(int i = head[noww];i;i = edge[i].next) { int vj = edge[i].vj; if(vj == father)continue; dfs2(vj,noww); qianzhui[noww] += qianzhui[vj]; } } bool check(int x) { memset(qianzhui,0,sizeof(qianzhui)); tmp = 0;top = 0; for(int i = 1;i <= m;i++) { if(cost[i] > x) { top++; qianzhui[be[i]]++; qianzhui[ed[i]]++; qianzhui[lca[i]] -= 2; } } dfs2(1,0); for(int i = 2;i <= n;i++) if(qianzhui[i] >= top && cos[i] - cos[fa[i][0]] > tmp)tmp = cos[i] - cos[fa[i][0]]; return maxx - tmp <= x; } int main() { n = read();m = read(); for(int i = 1;i < n;i++) { int vi = read(),vj = read(),wei = read(); push(vi,vj,wei); push(vj,vi,wei); } dfs(1,0); for(int i = 1;i <= 19;i++) for(int j = 1;j <= n;j++) fa[j][i] = fa[fa[j][i - 1]][i - 1]; for(int i = 1;i <= m;i++) { int vi = read(),vj = read(); be[i] = vi;ed[i] = vj; lca[i] = query_lca(vi,vj); cost[i] = cos[vi] + cos[vj] - 2 * cos[lca[i]]; maxx = max(maxx,cost[i]); } int l = 0,r = 300000000; while(l + 1 < r) { int mid = (l + r) >> 1; if(check(mid))r = mid; else l = mid; } printf("%d",check(l) ? l:r); return 0; }
以上是关于Noip2015day2解题报告的主要内容,如果未能解决你的问题,请参考以下文章