2016 Multi-University Training Contest 4题解报告

本文提供了2016年多校训练赛的部分题目解析,包括字符串处理、动态规划、数据结构等算法题目的详细解答及代码实现。

此文章可以使用目录功能哟↑(点击上方[+])

多校将近过半,此时只能用一幅图形容自己...


2016 Multi-University Training Contest 4官方题解

链接→2016 Multi-University Training Contest 4

 Problem 1001 Another Meaning

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

As is known to all, in many cases, a word has two meanings. Such as “hehe”, which not only means “hehe”, but also means “excuse me”. 

Today, ?? is chating with MeiZi online, MeiZi sends a sentence A to ??. ?? is so smart that he knows the word B in the sentence has two meanings. He wants to know how many kinds of meanings MeiZi can express.

 Input

The first line of the input gives the number of test cases T; T test cases follow.
Each test case contains two strings A and B, A means the sentence MeiZi sends to ??, B means the word B which has two menaings. string only contains lowercase letters.

Limits
T <= 30
|A| <= 100000
|B| <= |A|


 Output

For each test case, output one line containing “Case #x: y” (without quotes) , where x is the test case number (starting from 1) and y is the number of the different meaning of this sentence may be. Since this number may be quite large, you should output the answer modulo 1000000007.

 Sample Input

4
hehehe
hehe
woquxizaolehehe
woquxizaole
hehehehe
hehe
owoadiuhzgneninougur
iehiehieh

 Sample Output

Case #1: 3
Case #2: 2
Case #3: 5
Case #4: 1

Hint
In the first case, “hehehe” can have 3 meaings: “*he”, “he*”, “hehehe”.
In the third case, “hehehehe” can have 5 meaings: “*hehe”, “he*he”, “hehe*”, “**”, “hehehehe”.

 Problem Idea

解题思路:

【题意】
T组测试数据,每组包含两个字符串A和B

字符串B有两种含义,一种是其本身,另一种暂时用"*"表示

问字符串A有几种含义


【类型】
KMP+DP

【分析】
因为凡是字符串A包含字符串B的位置,均会有两种含义

故,我们可以先用KMP求解出字符串A中包含B的位置,本人记录字符串A包含字符串B时,B的最后一个字符在A中的位置

比如样例1,我记录的位置为4 6

然后令dp[i]表示,字符串A前i个字符构成的串的含义数

假设字符串A长度为len,字符串B长度为l

那么,当i所在位置已被标记时,意味着,此处恰好为包含字符串B的最后一个位置

那此处情况取决于i-l位置,若i-l位置恰好在包含字符串B的其中

那么,dp[i]=(dp[i-l]+dp[i-1])%mod

否则,dp[i]=(dp[i-l]*2)%mod

若,当前i位置未被标记,那当前位置并没有匹配的字符串B,故

dp[i]=dp[i-1]

然后从头扫一遍即可,结果为dp[len]

【时间复杂度&&优化】
O(nlogn)

题目链接→HDU 5763 Another Meaning

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 70;
const int inf = 1000000007;
const int mod = 1000000007;
char a[N],b[N];
int n[N],s[N];
bool v[N];
__int64 dp[N];
void getnext()
{
    int i=0,j=-1,l=strlen(b);
    n[0]=-1;
    while(i<l)
    {
        if(j==-1|b[i]==b[j])
        {
            i++;j++;
            if(b[i]==b[j])
                n[i]=n[j];
            else
                n[i]=j;
        }
        else
            j=n[j];
    }
}
int kmp()
{
    getnext();
    int i=0,j=0,k=0,len=strlen(a),l=strlen(b);
    while(i<len)
    {
        if(j==-1|a[i]==b[j])
            i++,j++;
        else
            j=n[j];
        if(j==l)
            v[i]=true,s[k]=i,k++,j=n[j];
    }
    return k;
}
int main()
{
    int t,p=1,k,i,len,l,c;
    __int64 ans;
    scanf("%d",&t);
    while(t--)
    {
        ans=1;
        memset(dp,0,sizeof(dp));
        memset(v,false,sizeof(v));
        scanf("%s",a);
        scanf("%s",b);
        len=strlen(a);
        l=strlen(b);
        k=kmp();
        dp[0]=1;
        for(i=1;i<=len;i++)
        {
            if(v[i]&&i>=l)
            {
                c=lower_bound(s,s+k,i-l)-s;
                if(i>s[c])
                    dp[i]=(dp[i-l]+dp[i-1])%mod;
                else
                    dp[i]=(dp[i-l]*2)%mod;
            }
            else
                dp[i]=dp[i-1];
            //printf("%d %I64d\n",i,dp[i]);
        }
        printf("Case #%d: %I64d\n",p++,dp[len]);
    }
    return 0;
}

 Problem 1010 The All-purpose Zero

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

?? gets an sequence S with n intergers(0 < n <= 100000,0<= S[i] <= 1000000).?? has a magic so that he can change 0 to any interger(He does not need to change all 0 to the same interger).?? wants you to help him to find out the length of the longest increasing (strictly) subsequence he can get.

 Input

The first line contains an interger T,denoting the number of the test cases.(T <= 10)
For each case,the first line contains an interger n,which is the length of the array s.
The next line contains n intergers separated by a single space, denote each number in S.


 Output

For each test case, output one line containing “Case #x: y”(without quotes), where x is the test case number(starting from 1) and y is the length of the longest increasing subsequence he can get.

 Sample Input

2
7
2 0 2 1 2 0 5
6
1 2 3 3 0 0

 Sample Output

Case #1: 5
Case #2: 5

Hint
In the first case,you can change the second 0 to 3.So the longest increasing subsequence is 0 1 2 3 5.

 Problem Idea

解题思路:

【题意】
题意很简单,给你一个序列,其中的0可以换成任意整数,包括负数

问该序列的最长上升子序列的长度为多少


【类型】
LIS变形题

【分析】
貌似去年多校也有一题LIS的变形题

然而dp是我的软肋

大神般的思路,我们只能先理解透彻

因为0可以充当任意整数,显然尽可能放入最长上升子序列中必定是正确的

为什么呢?

①情况一:有缝插入

对于0 1 0 5 0 0 9这类序列

除去0以外的最长上升子序列为1 5 9

因为此时相邻元素间的间隔都够放入0,故可有缝插入

②情况二:无缝替换

对于1 0 2 0 3这类序列

除去0以外的最长上升子序列为1 2 3

此时,相邻元素间没有间隔可以插入0,按照我们最初的思路是尽可能把0放入

故0对于最长上升子序列的贡献就是替换掉2 3

分析完毕.

因此我们可以把0拿出来,对剩下的做O(nlogn)的LIS,统计结果的时候再加上0的数量。为了保证严格递增,我们可以将每个权值s[i]减去i前面0的个数,再做LIS,就能保证结果是严格递增的。

需注意的一点是,若整个序列全为0时,若你的LIS程序初始长度为1,那么就需要特判0的情况

【时间复杂度&&优化】
O(nlogn)

题目链接→HDU 5773 The All-purpose Zero

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 100005;
const int inf = 1000000007;
const int mod = 1000000007;
int  a[N], f[N], d[N], s[N];    // f[i]用于记录 a[0...i]的最大长度
int bsearch(const int *f, int size, const int &a)
{
    int  l=0, r=size-1;
    while( l <= r )
    {
        int  mid = (l+r)>>1;
        if( a > d[mid-1] && a <= d[mid] )
            return mid;                // >&&<= 换为: >= && <
        else if( a <d[mid] )
                r = mid-1;
        else l = mid+1;
    }
}
int LIS(const int *a, const int &n)
{
    int  i, j, size = 1;
    d[0] = a[0]; f[0] = 1;
    for( i=1; i < n; ++i )
    {
        if( a[i] <= d[0] )             // <= 换为: <
            j = 0;
        else if( a[i] > d[size-1] ) // > 换为: >=
            j = size++;
        else
            j = bsearch(d, size, a[i]);

        d[j] = a[i]; f[i] = j+1;
    }
    return size;
}
int main()
{
    int  t,i,n,k,p=1,q;
    scanf("%d",&t);
    while(t--)
    {
        memset(f,0,sizeof(f));
        memset(d,0,sizeof(d));
        scanf("%d",&n);
        for( q=k=i=0; i < n; ++i )
        {
            scanf("%d", &s[i]);
            if(s[i]!=0)
                a[q++]=s[i]-k;
            else
                k++;
        }
        if(k!=n)
            printf("Case #%d: %d\n",p++,LIS(a, q)+k);
        else
            printf("Case #%d: %d\n",p++,k);
    }
    return 0;
}

 Problem 1011 Where Amazing Happens

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

As the premier men's professional basketball league in the world, the National Basketball Association (NBA) has witnessed many superstars, legendary teams and precious friendships.


Here is a list of every season’s champion from the league's inception in 1946 to 2015.
Season Champion
2015-16 Cleveland Cavaliers
2014-15 Golden State Warriors
2013-14 San Antonio Spurs
2012-13 Miami Heat
2011-12 Miami Heat
2010-11 Dallas Mavericks
2009-10 L.A. Lakers
2008-09 L.A. Lakers
2007-08 Boston Celtics
2006-07 San Antonio Spurs
2005-06 Miami Heat
2004-05 San Antonio Spurs
2003-04 Detroit Pistons
2002-03 San Antonio Spurs
2001-02 L.A. Lakers
2000-01 L.A. Lakers
1999-00 L.A. Lakers
1998-99 San Antonio Spurs
1997-98 Chicago Bulls
1996-97 Chicago Bulls
1995-96 Chicago Bulls
1994-95 Houston Rockets
1993-94 Houston Rockets
1992-93 Chicago Bulls
1991-92 Chicago Bulls
1990-91 Chicago Bulls
1989-90 Detroit Pistons
1988-89 Detroit Pistons
1987-88 L.A. Lakers
1986-87 L.A. Lakers
1985-86 Boston Celtics
1984-85 L.A. Lakers
1983-84 Boston Celtics
1982-83 Philadelphia 76ers
1981-82 L.A. Lakers
1980-81 Boston Celtics
1979-80 L.A. Lakers
1978-79 Seattle Sonics
1977-78 Washington Bullets
1976-77 Portland Trail Blazers
1975-76 Boston Celtics
1974-75 Golden State Warriors
1973-74 Boston Celtics
1972-73 New York Knicks
1971-72 L.A. Lakers
1970-71 Milwaukee Bucks
1969-70 New York Knicks
1968-69 Boston Celtics
1967-68 Boston Celtics
1966-67 Philadelphia 76ers
1965-66 Boston Celtics
1964-65 Boston Celtics
1963-64 Boston Celtics
1962-63 Boston Celtics
1961-62 Boston Celtics
1960-61 Boston Celtics
1959-60 Boston Celtics
1958-59 Boston Celtics
1957-58 St. Louis Hawks
1956-57 Boston Celtics
1955-56 Philadelphia Warriors
1954-55 Syracuse Nats
1953-54 Minneapolis Lakers
1952-53 Minneapolis Lakers
1951-52 Minneapolis Lakers
1950-51 Rochester Royals
1949-50 Minneapolis Lakers
1948-49 Minneapolis Lakers
1947-48 Baltimore Bullets
1946-47 Philadelphia Warriors

(quoted from http://www.nba.com/history/nba-season-recaps/)

Given the team name, it won’t be difficult for you to count how many times this team(with exactly the same name) has made amazing happen.

 Input

The first line gives the number of test cases. Each case contains one string S representing the team to be queried.
T<=30.S consists of English letters, digits, punctuations and spaces. And 1<=length(S)<=30.


 Output

For each test case, output one line containing "Case #x: y", where x is the test case number (starting from 1) and y is the times this team has won the championship according to the list above.


 Sample Input

2
Cleveland Cavaliers
Oklahoma City Thunder

 Sample Output

Case #1: 1
Case #2: 0

 Problem Idea

解题思路:

【题意】
简单来说,就是给你一个字符串,问你在题目描述里的清单中出现了几次


【类型】
签到题

【分析】
其实这题麻烦就麻烦在处理题目描述中长长的清单

可以写个代码处理一下,当然也可以毅力帝一下,把整个清单手动保存到字符数组中

需要注意的就是要把清单前面的时间去掉

去掉的时候小心一些,别删多了就行

剩下的就是一发暴力比较,交给strcmp函数就行

【时间复杂度&&优化】
O(T)

题目链接→HDU 5774 Where Amazing Happens

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 105;
const int M = 70;
const int inf = 1000000007;
const int mod = 1000000007;
char s[N],ch[M][N]={
"Cleveland Cavaliers",
"Golden State Warriors",
"San Antonio Spurs",
"Miami Heat",
"Miami Heat",
"Dallas Mavericks",
"L.A. Lakers",
"L.A. Lakers",
"Boston Celtics",
"San Antonio Spurs",
"Miami Heat",
"San Antonio Spurs",
"Detroit Pistons",
"San Antonio Spurs",
"L.A. Lakers",
"L.A. Lakers",
"L.A. Lakers",
"San Antonio Spurs",
"Chicago Bulls",
"Chicago Bulls",
"Chicago Bulls",
"Houston Rockets",
"Houston Rockets",
"Chicago Bulls",
"Chicago Bulls",
"Chicago Bulls",
"Detroit Pistons",
"Detroit Pistons",
"L.A. Lakers",
"L.A. Lakers",
"Boston Celtics",
"L.A. Lakers",
"Boston Celtics",
"Philadelphia 76ers",
"L.A. Lakers",
"Boston Celtics",
"L.A. Lakers",
"Seattle Sonics",
"Washington Bullets",
"Portland Trail Blazers",
"Boston Celtics",
"Golden State Warriors",
"Boston Celtics",
"New York Knicks",
"L.A. Lakers",
"Milwaukee Bucks",
"New York Knicks",
"Boston Celtics",
"Boston Celtics",
"Philadelphia 76ers",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"Boston Celtics",
"St. Louis Hawks",
"Boston Celtics",
"Philadelphia Warriors",
"Syracuse Nats",
"Minneapolis Lakers",
"Minneapolis Lakers",
"Minneapolis Lakers",
"Rochester Royals",
"Minneapolis Lakers",
"Minneapolis Lakers",
"Baltimore Bullets",
"Philadelphia Warriors"};
int main()
{
    int t,i,k,p=1;
    scanf("%d\n",&t);
    while(t--)
    {
        k=0;
        gets(s);
        for(i=0;i<M;i++)
            if(strcmp(s,ch[i])==0)
                k++;
        printf("Case #%d: %d\n",p++,k);
    }
    return 0;
}

 Problem 1012 Bubble Sort

Accept: 0    Submit: 0
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit : 65536/65536 K (Java/Others)

 Problem Description

P is a permutation of the integers from 1 to N(index starting from 1).

Here is the code of Bubble Sort in C++.

for(int i=1;i<=N;++i)

for(int j=N,t;j>i;—j)

if(P[j-1] > P[j])

t=P[j],P[j]=P[j-1],P[j-1]=t;

After the sort, the array is in increasing order. ?? wants to know the absolute values of difference of rightmost place and leftmost place for every number it reached.

 Input

The first line of the input gives the number of test cases T; T test cases follow.
Each consists of one line with one integer N, followed by another line with a permutation of the integers from 1 to N, inclusive.

limits
T <= 20
1 <= N <= 100000
N is larger than 10000 in only one case.


 Output

For each test case output “Case #x: y1 y2 … yN” (without quotes), where x is the test case number (starting from 1), and yi is the difference of rightmost place and leftmost place of number i.

 Sample Input

2
3
3 1 2
3
1 2 3

 Sample Output

Case #1: 1 1 2
Case #2: 0 0 0

Hint
In first case, (3, 1, 2) -> (3, 1, 2) -> (1, 3, 2) -> (1, 2, 3)
the leftmost place and rightmost place of 1 is 1 and 2, 2 is 2 and 3, 3 is 1 and 3
In second case, the array has already in increasing order. So the answer of every number is 0.

 Problem Idea

解题思路:

【题意】
给你一个1~n的排列,问冒泡排序过程中,数字i(1<=i<=n)所到达的最左位置与最右位置的差值的绝对值是多少


【类型】
树状数组

【分析】
这题难其实难在题意理解上

或许只是因为我理解能力太差

一开始以为只比较数字i开始位置和最终位置的差值

没想到是过程中到达的最左位置和最右位置→_→

首先,我们要清楚,冒泡排序大致是个什么过程

理解之后,容易发现,数字i多能到达的最左位置为min(s[i],i)

i为它的初始位置,s[i]为它的最终位置(因为最后是排好序,这个数是多少,就排在哪个位置,故为s[i])

那最右位置呢?

就是判断数i初始时,右边有多少个数比i小,这个就能用树状数组来求解了

循环从右到左,对于数s[i],我们只需判断它右边1~s[i]-1中有几个数即可


【时间复杂度&&优化】
O(nlogn)

题目链接→HDU 5775 Bubble Sort

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-8
#define LL long long
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100001;
const int M = 70;
const int inf = 1000000007;
const int mod = 1000000007;
int s[N],l[N],r[N],c[N];
int lowbit(int t)
{//计算c[t]展开的项数
    return t&(-t);
}
void update(int i,int x)
{
    while(i<N)
    {
        c[i]=c[i]+x;
        i+=lowbit(i);
    }
}
int Sum(int n) //求前n项的和.
{
    int sum=0;
    while(n>0)
    {
         sum+=c[n];
         n-=lowbit(n);
    }
    return sum;
}
int main()
{
    int t,n,p=1,i;
    scanf("%d",&t);
    while(t--)
    {
        memset(c,0,sizeof(c));
        scanf("%d",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%d",&s[i]);
            l[s[i]]=min(i,s[i]);
        }
        for(i=n;i>0;i--)
        {
            r[s[i]]=i+Sum(s[i]-1);
            update(s[i],1);
        }
        printf("Case #%d:",p++);
        for(i=1;i<=n;i++)
            printf(" %d",abs(l[i]-r[i]));
        puts("");
    }
    return 0;
}

菜鸟成长记

评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值