BestCoder Round #74 (div.2) A.LCP Array & B.Shortest Path

LCP Array

 
 Accepts: 131
 
 Submissions: 1352
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
Problem Description

Peter has a string ss1s2...sns=s1s2...sn, let isisi1...snsuffi=sisi+1...sn be the suffix start with ii-th character of ss. Peter knows the lcp (longest common prefix) of each two adjacent suffixes which denotes as aiii11inai=lcp(suffi,suffi+1)(1i<n).

Given the lcp array, Peter wants to know how many strings containing lowercase English letters only will satisfy the lcp array. The answer may be too large, just print it modulo 1097109+7.

Input

There are multiple test cases. The first line of input contains an integer TT indicating the number of test cases. For each test case:

The first line contains an integer nn (2n1052n105) -- the length of the string. The second line contains n1n1 integers: a1a2...an1a1,a2,...,an1 0ain(0ain).

The sum of values of nn in all test cases doesn't exceed 106106.

Output

For each test case output one integer denoting the answer. The answer must be printed modulo 1097109+7.

Sample Input
3
3
0 0
4
3 2 1
3
1 2
Sample Output
16250
26
0

题意:
Peter有一个字符串ss1s2...sns=s1s2...sn, 令isisi1...snsuffi=sisi+1...snssii字符开头的后缀. Peter知道任意两个相邻的后缀的最长公共前缀aiii11inai=lcp(suffi,suffi+1)(1i<n).

现在给你数组aa, Peter有多少个仅包含小写字母的字符串满足这个数组. 答案也许会很大, 你只要输出对1097109+7取模的结果即可.

乍一看以为是水题,判断一下a[i]是否为0不就可以了吗,不为0的话乘上25即可。结果发现这题根本不是坑你怎么算个数,而是坑你什么时候输出0……

一个小时wa了9次我也是醉了,就这样与div1擦肩而过……

下面仔细说下思路:假设如果a[i]=5,那么毫无疑问正确的字符串应该满足a[i+1]=4,a[i+2]=3.......因此以sum=26为底数,每次碰上a[i]!=0 往后跳即可(也可以直接跳过多个位置直接到达下一个a[i]=0的位置),若碰上a[i]=0,则乘上25。

以上为字符串符合正确的情况下的结果,而错误情况包括:a[i]>0而后续a[i+1]等未逐一递减至0;a[i]+i>n,即超过字符串长度。

做题过程中莫名其妙的以为a[i]只能递减至0,之后必须为0,实际上存在如4 3 2 1 0 3 2 1 0这样的a[i]排列组合,而不是一连串的0。明白这些,很快就A了。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3
const int N=100005;
const int mod=1e9+7;

int a[N];

long long sum=0;

int main(){
    int t,n;
    cin>>t;
    while (t--) {
        a[0]=INF;
        sum=26;
        cin>>n;
        for (int i=1; i<=n-1; i++) {
            scanf("%d",&a[i]);
        }
        int flag=1;
        for (int i=1; i<=n-1; i++) {
            if (a[i]+i>n) {
                flag=0;
                break;
            }
            if (a[i]>=a[i-1]&&a[i]&&a[i-1]) {
                flag=0;
                break;
            }
        }
        for (int i=2; i<=n-1; i++) {
            if (a[i-1]-a[i]!=0) {
                for (int j=i; j<=i-2+a[i-1]; j++) {
                    if (a[j-1]-a[j]!=1) {
                        flag=0;
                        break;
                    }
                }
            }
        }
        int i=1;
        while (i<=n-1) {
            if (a[i]==0) {
                sum*=25;
                sum%=mod;
            }
            i++;
        }
        if (flag)   cout<<sum<<endl;
        else cout<<"0"<<endl;
    }
    return 0;
}


Shortest Path

 
 Accepts: 40
 
 Submissions: 610
 Time Limit: 4000/2000 MS (Java/Others)
 
 Memory Limit: 131072/131072 K (Java/Others)
Problem Description

There is a path graph GVEG=(V,E) with nn vertices. Vertices are numbered from 11 to nn and there is an edge with unit length between ii and i1i+1 1in(1i<n). To make the graph more interesting, someone adds three more edges to the graph. The length of each new edge is 11.

You are given the graph and several queries about the shortest path between some pairs of vertices.

Input

There are multiple test cases. The first line of input contains an integer TT, indicating the number of test cases. For each test case:

The first line contains two integer nn and mm 1nm105(1n,m105) -- the number of vertices and the number of queries. The next line contains 6 integers a1b1a2b2a3b3a1,b1,a2,b2,a3,b3 1a1a2a3b1b2b3n(1a1,a2,a3,b1,b2,b3n), separated by a space, denoting the new added three edges are a1b1(a1,b1)a2b2(a2,b2)a3b3(a3,b3).

In the next mm lines, each contains two integers sisi and titi 1sitin(1si,tin), denoting a query.

The sum of values of mm in all test cases doesn't exceed 106106.

Output

For each test cases, output an integer Si1mizi1097S=(i=1mizi) mod (109+7), where zizi is the answer for ii-th query.

Sample Input
1
10 2
2 4 5 7 8 10
1 5
3 1
Sample Output
7

题意:给你n个的点,用一根线串联起来,相邻点之间距离为1。接下来给你3条边分别连接其中的3组点。

之后m个询问,询问包含2个点。输出在i=1-m个询问中,2个点之间的距离*i,对1e9+7取模。

昨晚做的时候第一题把我错麻木了,看题没什么思路,想着无脑最短路才发现n,m高达1e5,最后无奈没A。

最后看官方题解,简洁到无情,拿6个点建图floyd算完之后,复杂度居然是O(6^2*m),当时懵逼后想了想也没什么具体思路。

最后想出来贴切题解的的是将题中3条边的6个点进行floyd最短路计算,计算完毕后,假设询问的两个点为a和b,则假设a到b的过程中必经过6个点中任意一个,那么找到a到该点的最短路与b到该点的最短路,两者相加即可。而计算最短路时其实就是对6个点进行枚举,枚举必经过每一个点的过程。假设必经过6个点中的A,用之前floyd算出来的6个点最短路找到a点与b点到A点最短路(如先去B,由B到A等等,每个点计算6次,即达到6^2*m的复杂度。

做题时以为输入是a1,a2,a3,b1,b2,b3的顺序,还很好奇为什么输入顺序这么奇怪,wa了一小时发现是a1,b1……之后又发现计算最短路过程中忘记了a到b有可能不经过任意一点直接计算abs(b-a)即可。最后艰难的a了。

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
#define INF 0x3f3f3f3
const int N=100005;
const int mod=1e9+7;

int d[10][10],a[10];
int s[N],t[N];
long long sum=0;

int main(){
    int ti,n,m;
    cin>>ti;
    while (ti--) {
        sum=0;
        memset(d, 0, sizeof(d));
        cin>>n>>m;
        for (int i=1; i<=3; i++) {
            cin>>a[i]>>a[i+3];
        }
        for (int i=1; i<=m; i++) {
            scanf("%d %d",&s[i],&t[i]);
        }
        d[1][4]=d[4][1]=1;
        d[2][5]=d[5][2]=1;
        d[6][3]=d[3][6]=1;
        for (int i=1; i<=6; i++) {
            for (int j=1; j<=6; j++) {
                if (d[i][j]==0) {
                    d[i][j]=abs(a[i]-a[j]);
                }
            }
        }
        for (int k=1; k<=6; k++) {
            for (int i=1; i<=6; i++) {
                for (int j=1; j<=6; j++) {
                    if (d[i][j]>d[i][k]+d[k][j]) {
                        d[i][j]=d[i][k]+d[k][j];
                    }
                }
            }
        }
        int d1,d2,mind;
        for (int k=1; k<=m; k++) {
            mind=abs(s[k]-t[k]);
            for (int i=1; i<=6; i++) {
                d1=abs(s[k]-a[i]);
                d2=abs(t[k]-a[i]);
                for (int j=1; j<=6; j++) {
                    if (i==j) {
                        continue;
                    }
                    d1=min(d1, abs(a[j]-s[k])+d[j][i]);
                    d2=min(d2, abs(a[j]-t[k])+d[j][i]);
                }
                if (d1+d2<mind) {
                    mind=d1+d2;
                }
            }
            sum+=((long long)k*mind)%mod;
            sum%=mod;
        }
        cout<<sum<<endl;
    }
    return 0;
}

你可能感兴趣的:(BestCoder Round #74 (div.2) A.LCP Array & B.Shortest Path)