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",&note[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解题报告的主要内容,如果未能解决你的问题,请参考以下文章

noip2014Day2解题报告

NOIp2016 Day1&Day2 解题报告

noip2011提高组day1+day2解题报告

NOIP2015 解题报告

NOIP2016普及组复赛解题报告

$NOIP 2018 Day2$ 模拟考试 题解报告