zoukankan      html  css  js  c++  java
  • niop2015day2

    P2678 跳石头

    题目描述

    这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

    为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MM 块岩石(不能移走起点和终点的岩石)。

    输入输出格式

    输入格式:

    输入文件第一行包含三个整数 L,N,ML,N,M ,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L geq 1L1 且 N geq M geq 0NM0 。

    接下来 NN 行,每行一个整数,第 ii 行的整数 $D_i( 0 < D_i < L)$ , 表示第 ii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

    输出格式:

    输出文件只包含一个整数,即最短跳跃距离的最大值。

    输入输出样例

    输入样例#1: 复制
    25 5 2 
    2
    11
    14
    17 
    21
    输出样例#1: 复制
    4

    说明

    输入输出样例 1 说明:将与起点距离为 2 和 14 的两个岩石移走后,最短的跳跃距离为 4(从与起点距离 17 的岩石跳到距离 21 的岩石,或者从距离 21 的岩石跳到终点)。

    另:对于 20%的数据,0 ≤ M ≤ N ≤ 10。 对于50%的数据,0 ≤ M ≤ N ≤ 100。

    对于 100%的数据,0 ≤ M ≤ N ≤ 50,000,1 ≤ L ≤ 1,000,000,000。

    题解:二分距离

    #include <bits/stdc++.h>
    
    using namespace std;
    const int maxn = 50005;
    int dis[maxn];
    int L, M, N;
    bool check(int k){
        int t = 0, las = 0;
        for(int i = 1; i <= N+1; i++){
            if(dis[i] - las < k)
                t++;
            else las = dis[i];
            if(t > M)return 0;
        }
    
        return 1;
    }
    int main()
    {
        //freopen("stone.in","r",stdin);
        //freopen("stone.out","w",stdout);
        int ans;
        scanf("%d%d%d",&L,&N,&M);
        for(int i = 1; i <= N; i++)scanf("%d",&dis[i]);
        dis[N+1] = L;
        int lf = 0, rg = L;
        while(lf <= rg){
            int mid = (lf + rg) >> 1;
            if(check(mid))ans = mid, lf = mid + 1;
            else rg = mid - 1;
    
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

    P2679 子串

    题目描述

    有两个仅包含小写英文字母的字符串 AA 和 BB 。

    现在要从字符串 AA 中取出 kk 个互不重叠的非空子串,然后把这 kk 个子串按照其在字符串 AA 中出现的顺序依次连接起来得到一个新的字符串。请问有多少种方案可以使得这个新串与字符串 BB 相等?

    注意:子串取出的位置不同也认为是不同的方案。

    输入输出格式

    输入格式:

    第一行是三个正整数 n,m,kn,m,k ,分别表示字符串 AA 的长度,字符串 BB 的长度,以及问题描述中所提到的 kk ,每两个整数之间用一个空格隔开。

    第二行包含一个长度为 nn 的字符串,表示字符串 AA 。

    第三行包含一个长度为 mm 的字符串,表示字符串 BB 。

    输出格式:

    输出共一行,包含一个整数,表示所求方案数。

    由于答案可能很大,所以这里要求输出答案对 10000000071000000007 取模的结果。

    输入输出样例

    输入样例#1: 复制
    6 3 1 
    aabaab 
    aab
    输出样例#1: 复制
    2
    输入样例#2: 复制
    6 3 2 
    aabaab 
    aab
    输出样例#2: 复制
    7
    输入样例#3: 复制
    6 3 3 
    aabaab 
    aab
    输出样例#3: 复制
    7

    说明

    对于第 1 组数据:1≤n≤500,1≤m≤50,k=1;
    对于第 2 组至第 3 组数据:1≤n≤500,1≤m≤50,k=2;
    对于第 4 组至第 5 组数据:1≤n≤500,1≤m≤50,k=m;
    对于第 1 组至第 7 组数据:1≤n≤500,1≤m≤50,1≤k≤m;
    对于第 1 组至第 9 组数据:1≤n≤1000,1≤m≤100,1≤k≤m;

    对于所有 10 组数据:1≤n≤1000,1≤m≤200,1≤k≤m。

    题解:dp;果然又没想出方程

    先想到: dp[ i ][ j ][ k ] = dp[ i-1 ][ j-1 ][ k ] + dp[ i-1 ][ j-1 ][ k-1 ]; ( A[i] == B[j] )

    即:能匹配时,方案数为:单独使用当前字符为一个子串 + 与前面相连形成一个子串;

    稍微仔细一想就可以知道,这个DP式子是有问题的,如果不使用当前字符被遗漏了

    所以:

    设s[ i ][ j ][ k ]为A到了 i ,B到了 j ,已经用了 k 个子串, 并且一定用了当前字符(A[i])时的方案数。

    设f[ i ][ j ][ k ]为A到了 i ,B到了 j ,已经用了 k 个子串, 无论用不用当前字符(A[i])时的方案数总和。

    能转移的前提自然是 A[ i ] == B [ j ]啦。

    既然 A[i] 一定要用,那么依旧是两种情况:独自成一串 或 与前面的成一串。

    s[ i ][ j ][ k ] = f[ i-1 ][ j-1 ][ k-1 ] + s[ i-1 ][ j-1 ][ k ];

    f[ i ][ j ][ k ] 的来源也有两种: 使用当前字符 或 不使用当前字符

     f[ i ][ j ][ k ] = f[ i-1 ][ j ][ k ] + s[ i ][ j ][ k ];

    然后由于空间原因开滚动数组,注意中间转移时A[i]!=B[j] f 要赋值0,不然会影响后面 

    初始化 f[ i ][ 0 ][ 0 ] = 1, 不选也是一种方案

    #include <bits/stdc++.h>
    
    using namespace std;
    int f[2][505][505], s[2][505][505];
    char a[1005], b[1005];
    const int M = 1000000007;
    int main()
    {
        //freopen("substring.in","r",stdin);
        //freopen("substring.out","w",stdout);
        int n, m, k, ans = 0;
        scanf("%d%d%d",&n,&m,&k);
        scanf("%s%s",a+1,b+1);
        int u = 0;
        f[0][0][0]=1;
        for(int i = 1; i <= n; i++){
            u^=1;
            f[u][0][0] = 1;
            for(int j = 1; j <= m; j++)
            for(int kk = 1; kk <= k; kk++){
                if(a[i] == b[j])s[u][j][kk] = (f[u^1][j-1][kk-1] + s[u^1][j-1][kk]) % M;
                else s[u][j][kk] = 0;
                f[u][j][kk] = (f[u^1][j][kk] + s[u][j][kk]) % M;
                //printf("%d %d %d %d %d
    ",i,j,kk,f[u][j][kk],s[u][j][kk]);
            }    
        }
        
        printf("%d
    ",f[u][m][k]);
        return 0;
    }
    View Code

    P2680 运输计划

    题目描述

    公元 2044 年,人类进入了宇宙纪元。

    L 国有 nn 个星球,还有 n-1n1 条双向航道,每条航道建立在两个星球之间,这 n-1n1 条航道连通了 LL 国的所有星球。

    小 P 掌管一家物流公司, 该公司有很多个运输计划,每个运输计划形如:有一艘物流飞船需要从 u_iui 号星球沿最快的宇航路径飞行到 v_ivi 号星球去。显然,飞船驶过一条航道是需要时间的,对于航道 jj ,任意飞船驶过它所花费的时间为 t_jtj ,并且任意两艘飞船之间不会产生任何干扰。

    为了鼓励科技创新, L 国国王同意小 P 的物流公司参与 L 国的航道建设,即允许小P 把某一条航道改造成虫洞,飞船驶过虫洞不消耗时间。

    在虫洞的建设完成前小 P 的物流公司就预接了 mm 个运输计划。在虫洞建设完成后,这 mm 个运输计划会同时开始,所有飞船一起出发。当这 mm 个运输计划都完成时,小 P 的物流公司的阶段性工作就完成了。

    如果小 P 可以自由选择将哪一条航道改造成虫洞, 试求出小 P 的物流公司完成阶段性工作所需要的最短时间是多少?

    输入输出格式

    输入格式:

    第一行包括两个正整数 n, mn,m ,表示 L 国中星球的数量及小 P 公司预接的运输计划的数量,星球从 11 到 nn 编号。

    接下来 n-1n1 行描述航道的建设情况,其中第 ii 行包含三个整数 a_i, b_iai,bi 和 t_iti ,表示第 ii 条双向航道修建在 a_iai 与 b_ibi两个星球之间,任意飞船驶过它所花费的时间为 t_iti 。数据保证 1 leq a_i,b_i leq n1ai,bin 且 0 leq t_i leq 10000ti1000 。

    接下来 mm 行描述运输计划的情况,其中第 jj 行包含两个正整数 u_juj 和 v_jvj ,表示第 jj 个运输计划是从 u_juj 号星球飞往 v_jvj 号星球。数据保证 1 leq u_i,v_i leq n1ui,vin

    输出格式:

    输出文件只包含一个整数,表示小 P 的物流公司完成阶段性工作所需要的最短时间。

    输入输出样例

    输入样例#1: 复制
    6 3 
    1 2 3 
    1 6 4 
    3 1 7 
    4 3 6 
    3 5 5 
    3 6 
    2 5 
    4 5
    输出样例#1: 复制
    11

    说明

    所有测试数据的范围和特点如下表所示

    请注意常数因子带来的程序效率上的影响。

    题解:先想到树剖+树状数组的暴力,每个点修改,复杂度N*M*LogN,会T

    首先求出每个计划的路径长度 以及路径上的lca
    然后二分时间k
    统计 k<路径长的条数 cnt 并维护最大差值 rest 
    并且对于每条不合法的路径维护每个点的经过次数
    然后枚举点 如果经过次数==cnt说明每一条不合法的都经过他
    然后尝试把它建成虫洞 如果他对应边的权值>=dec 那么我们删掉它ans就合法了
    如果没有次数==cnt的,说明至少要建两个虫洞,直接舍掉 关键是统计每个点在非法路径中的经过次数 : 维护sum数组 对于每个非法的路径起点a b LCA(a,b)==s sum[a]++ sum[b]++ sum[s]-=2//因为边权下放了点权 在dfs记录访问逆序,好一次更新,不然就N^2的
    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    const int maxn = 300000+5, P = 20;
    int Mtim, tot, idx;
    int st[maxn], ed[maxn], anc[maxn][P+1], q[maxn], to[maxn];
    int dep[maxn], dist[maxn], dis[maxn], h[maxn], du[maxn], lca[maxn];
    struct edge{int v,w,nxt;}G[maxn<<1];
    void add(int u,int v,int t){G[++tot].v = v;G[tot].w = t;G[tot].nxt = h[u]; h[u] = tot;}
    void read(int &x){
        int f=1;x=0;char c=getchar();
        while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
        while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();}
        x*=f;
    }
    void dfs(int u, int fr){
        anc[u][0] = fr;
        for(int p = 1; p <= P; p++)
            anc[u][p] = anc[anc[u][p-1]][p-1];
        dep[u] = dep[fr] + 1;
        for(int i = h[u]; i; i = G[i].nxt){
            int v = G[i].v;
            if(v == fr)continue;
            to[v] = G[i].w;
            dis[v] = dis[u] + to[v];
            dfs(v, u);
        }
        q[++idx] = u;//访问逆序
    }
    int flca(int u, int v){
        if(dep[u] < dep[v])swap(u, v);
        int t = dep[u] - dep[v];
        for(int p=0; t; t>>=1, p++)
            if(t & 1)u = anc[u][p];
        if(u == v)return u;
        for(int p = P; p >= 0; p--)
            if(anc[u][p] != anc[v][p])
                u = anc[u][p], v = anc[v][p];
        return anc[u][0];
    }
    void init(){
        dfs(1, 0);
        for(int i = 1; i <= m; i++){
            lca[i] = flca(st[i], ed[i]);
            dist[i] = dis[st[i]] + dis[ed[i]] - 2*dis[lca[i]];
            Mtim = max(Mtim, dist[i]);
        }
    }
    bool check(int k){
        memset(du, 0, sizeof(du));//!
        int cnt = 0, rest = 0, hh = -1;
        for(int i = 1; i <= m; i++){
            if(dist[i] <= k)continue;
            cnt++;
            du[st[i]]++;du[ed[i]]++;
            du[lca[i]]-=2;
            rest = max(rest, dist[i] - k);
        }
        if(!cnt)return 1;
        for(int i = 1; i <= n; i++){
            int u = q[i];
            du[anc[u][0]] += du[u];
        }
        for(int i = 1; i <= n; i++)
            if(du[i] == cnt)hh = max(hh, to[i]);
        return rest <= hh;
    }
    void solve(){
        int lf = 0, rg = Mtim, ans = 0;
        while(lf <= rg){
            int mid = (lf + rg) >> 1;
            if(check(mid))ans = mid, rg = mid - 1;
            else lf = mid + 1;
        }
        printf("%d
    ",ans);
    }
    int main(){
       // freopen("transport.in","r",stdin);
       // freopen("transport.out","w",stdout);
        read(n),read(m);
        for(int i = 1; i < n; i++){
            int u, v, t;
            read(u),read(v),read(t);
            add(u,v,t);
            add(v,u,t);
        }
        for(int i = 1; i <= m; i++)
            read(st[i]), read(ed[i]);
        init();
        solve();
    }
    View Code
     
  • 相关阅读:
    数据结构-树与二叉树-思维导图
    The last packet successfully received from the server was 2,272 milliseconds ago. The last packet sent successfully to the server was 2,258 milliseconds ago.
    idea连接mysql报错Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property
    redis学习笔记
    AJAX校验注册用户名是否存在
    AJAX学习笔记
    JSON学习笔记
    JQuery基础知识学习笔记
    Filter、Listener学习笔记
    三层架构学习笔记
  • 原文地址:https://www.cnblogs.com/EdSheeran/p/8995289.html
Copyright © 2011-2022 走看看