hihocoder contest 94 1 2 4题目分析

Posted paulzjt

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hihocoder contest 94 1 2 4题目分析相关的知识,希望对你有一定的参考价值。

https://hihocoder.com/contest/offers94/problem/4

 

题目1 : 最短管道距离

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

在一张2D地图上有N座城市,坐标依次是(X1, Y1), (X2, Y2), ... (XN, YN)。  

现在H国要修建一条平行于X轴的天然气主管道。这条管道非常长,可以认为是一条平行于X轴的直线。  

小Ho想知道如何修建这条管道,可以使N座城市到管道的垂直距离之和最小。请你求出这个最小的距离之和。

输入

第一行包含一个整数N。  

以下N行每行包含两个整数Xi, Yi。  

1 <= N <= 100000  

0 <= Xi, Yi <= 1000000  

输出

一个整数,代表最小的距离之和。

样例输入
4  
0 0  
0 100  
100 0  
100 100
样例输出
200



题目2 : 字符删除

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

给定一个字符串S和包含N个单词的字典D = {W1, W2, .... WN},小Hi想知道他最少从S中删除多少个字符,才能得到一个字典中的单词。

输入

第一行包含一个整数N。  

第二行包含N个空格隔开的单词,单词都由小写字母组成。  

第三行包含字符串S,由小写字母组成。  

1 <= N <= 10000  

字典中单词总长度不超过1000000  

1 <= |S| <= 100000

输入保证一定有解。

输出

一个整数代表答案。

样例输入
5
cat chat hate has heat
sheate
样例输出
2



题目4 : 木板刷油漆

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

小Hi有N块木板,从左到右排成一排,其中第i块木板的高度是Ai。如下所示是有5块木板,高度依次是3, 5, 2, 4, 3。

     #   
     # #
    ## ##
    #####
    #####

小Hi计划将这些木板都刷上油漆。由于工具所限,他每次只能沿水平方向刷油漆。具体来说,小Hi每次可以粉刷一个高度为1,长度不限的矩形区域,只要区域范围内都是木板(不能有空)。  

小Hi想知道他要粉刷完所有木板至少需要粉刷几次。  

例如对于上面的例子,小Hi至少粉刷7次,如下所示。数字1表示第1次粉刷的区域、数字2表示第2次粉刷的区域……  

     7
     5 6
    33 44
    22222
    11111

输入

第一行包含一个整数N。  

第二行包含N个整数A1, A2, ... AN。  

1 <= N <= 100000  

1 <= Ai <= 100000

输出

一个整数代表答案

样例输入
5
3 5 2 4 3
样例输出
7



1931

因为是垂直距离,就转化为一维问题:给定数轴上点,寻找一个点到其他点的距离之和最小。 这个是一个经典问题:

当数轴上的点的数量是偶数的时候,A取在数轴上所有点按照其坐标排列,排在最中间的两个点中间

当数轴上的点的数量是奇数的时候,A取这些所有点按照其坐标排列,排在最中间的点当取好A之后求所有点到其距离之和即可

技术图片
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long  ll;
#define mem(A, X) memset(A, X, sizeof A)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))

ll y[100010];
ll n,sum;
int main()
{
  ios::sync_with_stdio(false);
  //freopen("local.in","r",stdin);

  while(cin>>n){
      sum=0;
      fori(i,1,n){
        int t;
        cin>>t>>y[i];
      }
      sort(y+1,y+n+1);
      ll pos;
      if(n%2==0){
        pos=y[n/2]+(y[n/2+1]-y[n/2])/2;
      } else {
        pos=y[n/2+1];
      }
      ll ans=0;
      fori(i,1,n) ans+=abs(pos-y[i]);
      cout<<ans<<endl;
  }

return 0;
}
View Code

 

 

1932

确实是两种处理方式,一种是将字符串构建一个tire树,然后遍历trie树(深度和层次优先遍历都行,只要在失配时剪枝终止掉从当前位置对应的子树就可以了。),在每一个节点处根据从头结点到当前节点构成的前缀字符串去整个文本字符串中寻找是否能够构成这个字符串就可以了。经过这样的trie树优化之后,运行效率会在给出的单词中有大量重复前缀的时候有明显提升。至于如何从当前的前缀字符串去找整个文本字符串中能否构成这个字符串,只要通过贪心加预处理的思路处理就可以了。具体处理方式:对于当前待匹配单词temp和文本字符串str,首先预处理文本字符串str中的每一个字符str[i]能够和另一个字符ch(字符a,b,c,d,e,…)连接起来的最近字符位置nextpos[i][ch-‘a’],由于对于两个相邻位置的字符str[i]、str[i+1],str[i+1]预处理出来的nextpos[i+1][ch-‘a’]必然也是str[i]的最近字符位置,唯一一个不同的就是str[i+1]字符本身因为紧挨着str[i],所以str[i]到达str[i+1]这个字符的最近字符位置就是i+1这个位置。由此,只要从右至左依次递推出所有的nextpos信息,然后再在每次匹配temp的时候,按照temp字符本身从左到右的顺序依次按照处理好的字符转移信息就可以了。 预处理、dp、字符串、trie、贪心

  • 实现的时候,忘记在处理寻找temp第一个字符对应的位置的时候break了,导致wa了一次。
  • 参考
技术图片
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long  ll;
#define mem(A, X) memset(A, X, sizeof A)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))


string dict[10005];
string str;
int nextpos[100005][29]; // a->0
int n;
int ans;
int main()
{
  ios::sync_with_stdio(false);
  //freopen("local.in","r",stdin);
  while(cin>>n){
    fori(i,1,n) cin>>dict[i];
    cin>>str;
    int len=str.size();
    fori(i,1,26) nextpos[len-1][i-1]=-1;
    ford(i,str.size()-2,0){
        fori(j,0,25) nextpos[i][j]=nextpos[i+1][j];
        nextpos[i][str[i+1]-a]=i+1;
        // cout<<"No."<<i<<": "<<str[i]<<" ";
        // fori(j,0,25) cout<<nextpos[i][j]<<" ";
        // cout<<endl;
    }
    ans=100000000;
    fori(i,1,n){
        string temp=dict[i];
        int pos=-1;
        fori(j,0,len-1){
            if(str[j]==temp[0]) {pos=j;break;}
        }
        if(pos!=-1){
            fori(j,1,temp.size()-1){
                int t=nextpos[pos][temp[j]-a];
                if(t!=-1){
                    if(j==temp.size()-1 )  ans=min(ans, (int)str.size()-(int)temp.size());
                    pos=t;
                }
                else{
                    break;
                }
            }
        }
    }
    cout<<ans<<endl;
  }

return 0;
}
View Code

 

1934

多画一些样例就能够想到,累加所有的delta增量就是答案,开头增加一个0开头。

技术图片
#include <iostream>
#include <cstring>
#include <cstdio>
#include <string>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <cmath>
#include <bitset>
#include <vector>
#include <sstream>
#include <cstdlib>
#include <algorithm>
using namespace std;
typedef long long  ll;
#define mem(A, X) memset(A, X, sizeof A)
#define foreach(e,x) for(__typeof(x.begin()) e=x.begin();e!=x.end();++e)
#define fori(i,l,u) for(ll (i)=(ll)(l);(i)<=(ll)(u);++(i))
#define ford(i,l,u) for(ll (i)=(ll)(l);(i)>=(ll)(u);--(i))

int n;
int a[100005];
ll ans;
int main()
{
  ios::sync_with_stdio(false);
  //freopen("local.in","r",stdin);
  while(cin>>n){
      fori(i,1,n) cin>>a[i];
      ans=0;
      a[0]=0;
      fori(i,1,n) if(a[i]>a[i-1]) ans+=a[i]-a[i-1];
      cout<<ans<<endl;
  }

return 0;
}
View Code

 



以上是关于hihocoder contest 94 1 2 4题目分析的主要内容,如果未能解决你的问题,请参考以下文章

leetcodeWeekly Contest 94

hihoCoder 数组重排

hihoCoder太阁最新面经算法竞赛15

hihoCoder week3 KMP算法

Hihocoder 太阁最新面经算法竞赛18

hihoCoder week6 01背包