2015 Multi-University Training Contest 9(区间dp)

Expression

Problem Description

Teacher Mai has n numbers a1,a2,⋯,anand n−1 operators(“+”, “-” or “*”)op1,op2,⋯,opn−1, which are arranged in the form a1 op1 a2 op2 a3 ⋯ an.

He wants to erase numbers one by one. In i-th round, there are n+1−i numbers remained. He can erase two adjacent numbers and the operator between them, and then put a new number (derived from this one operation) in this position. After n−1 rounds, there is the only one number remained. The result of this sequence of operations is the last number remained.

He wants to know the sum of results of all different sequences of operations. Two sequences of operations are considered different if and only if in one round he chooses different numbers.

For example, a possible sequence of operations for “1+4∗6−8∗3” is 1+4∗6−8∗3→1+4∗(−2)∗3→1+(−8)∗3→(−7)∗3→−21.

Input

There are multiple test cases.

For each test case, the first line contains one number n(2≤n≤100).

The second line contains n integers a1,a2,⋯,an(0≤ai≤109).

The third line contains a string with length n−1 consisting “+”,”-” and “*”, which represents the operator sequence.

Output

For each test case print the answer modulo 109+7.

Sample Input

3
3 2 1
-+
5
1 4 6 8 3
+-

Sample Output

2
999999689
Hint
Two numbers are considered different when they are in different positions.
这里写图片描述

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=110;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N;
char s[maxn];
LL dp[maxn][maxn];
LL C[maxn][maxn],f[maxn];
int main(){
    for(int i=0;i<maxn;i++){
        for(int j=0;j<=i;j++){
            if(i==j||j==0)C[i][j]=1;
            else{
                C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
            }
        }
    }
    f[0]=1;
    for(int i=1;i<maxn;i++){
        f[i]=(f[i-1]*i)%MOD;
    }
    while(scanf("%d",&N)!=EOF){
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=N;i++)scanf("%I64d",&dp[i][i]);
        scanf("%s",s+1);
        for(int l=2;l<=N;l++){
            for(int i=1;i+l-1<=N;i++){
                int j=i+l-1;
                dp[i][j]=0;
                for(int k=i;k<j;k++){
                    LL t=0;
                    if(s[k]=='*'){
                        t=dp[i][k]*dp[k+1][j]%MOD;
                    } else if(s[k]=='+'){
                        t=(dp[i][k]*f[j-k-1]+dp[k+1][j]*f[k-i])%MOD;
                    } else if(s[k]=='-'){
                        t=(dp[i][k]*f[j-k-1]-dp[k+1][j]*f[k-i])%MOD;
                    }
                    dp[i][j]=(dp[i][j]+t*C[j-i-1][k-i])%MOD;
                }
            }
        }
        printf("%I64d\n",(dp[1][N]+MOD)%MOD);
    }
    return 0;
}

Too Simple

Problem Description

Rhason Cheung had a simple problem, and asked Teacher Mai for help. But Teacher Mai thought this problem was too simple, sometimes naive. So she ask you for help.

Teacher Mai has m functions f1,f2,⋯,fm:{1,2,⋯,n}→{1,2,⋯,n}(that means for all x∈{1,2,⋯,n},f(x)∈{1,2,⋯,n}). But Rhason only knows some of these functions, and others are unknown.

She wants to know how many different function series f1,f2,⋯,fm there are that for every i(1≤i≤n),f1(f2(⋯fm(i)))=i. Two function series f1,f2,⋯,fm and g1,g2,⋯,gm are considered different if and only if there exist i(1≤i≤m),j(1≤j≤n),fi(j)≠gi(j).

Input

For each test case, the first lines contains two numbers n,m(1≤n,m≤100).

The following are m lines. In i-th line, there is one number −1 or n space-separated numbers.

If there is only one number −1, the function fi is unknown. Otherwise the j-th number in the i-th line means fi(j).

Output

For each test case print the answer modulo 109+7.

Sample Input

3 3
1 2 3
-1
3 2 1

Sample Output

1
Hint
The order in the function series is determined. What she can do is to assign the values to the unknown functions.

思路:统计有多少没有确定的函数,假如有cnt个,那么答案就是 (N!)cnt1 ,然后判断一下是不是能够符合条件,不能符合条件的可能是存在不是单射的函数,或者是i变换之后不能还是i

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=110;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,M;
int a[maxn][maxn];
bool vis[maxn];
LL pow_mul(LL x,int n){
    LL res=1;
    while(n){
        if(n&1)res=res*x%MOD;
        x=x*x%MOD;
        n>>=1;
    }
    return res;
}
LL f[maxn];
int main(){
    f[0]=1;
    for(int i=1;i<maxn;i++){
        f[i]=f[i-1]*i%MOD;
    }
    while(scanf("%d%d",&N,&M)!=EOF){
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=M;i++){
            scanf("%d",&a[i][1]);
            if(a[i][1]==-1)vis[i]=1;
            else {
                for(int j=2;j<=N;j++){
                    scanf("%d",&a[i][j]);
                }
            }
        }
        LL ans=1;
        int cnt=0;
        for(int i=1;i<=M;i++){
            if(vis[i])cnt++;
        }
        if(cnt)ans=pow_mul(f[N],cnt-1);
        int x=-1;
        for(int i=1;i<=M;i++){
            if(vis[i]){
                x=i-1;
                break;
            }
        }
        bool flag=true;
        for(int i=1;i<=M;i++){
            if(a[i][1]==-1)continue;
            memset(vis,0,sizeof(vis));
            for(int j=1;j<=N;j++){
                vis[a[i][j]]=1;
            }
            for(int j=1;j<=N;j++){
                if(!vis[j]){
                    flag=false;
                    break;
                }
            }
            if(!flag)break;
        }
        if(!flag){
            printf("0\n");
            continue;
        }
        if(x==-1){
            memset(vis,0,sizeof(vis));
            flag=true;
            for(int i=1;i<=N;i++){
                int y=a[M][i];
                for(int j=M-1;j>=1;j--){
                    y=a[j][y];
                }
                if(y!=i){
                    flag=false;
                    break;
                }
            }
            if(!flag){
                printf("0\n");
                continue;
            }
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

Arithmetic Sequence

Problem Description

A sequence b1,b2,⋯,bn are called (d1,d2)-arithmetic sequence if and only if there exist i(1≤i≤n) such that for every j(1≤j

Input

There are multiple test cases.

For each test case, the first line contains three numbers n,d1,d2(1≤n≤105,|d1|,|d2|≤1000), the next line contains n integers a1,a2,⋯,an(|ai|≤109).

Output

For each test case, print the answer.

Sample Input

5 2 -2
0 2 0 -2 0
5 2 3
2 3 3 3 3

Sample Output

12
5

思路:统计一下连续的公差x有多少个,然后扫一遍,相邻的两个公差如果满足条件,乘起来累加答案就行了,要注意d1==d2的情况

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=1010;
const int MOD=1e9+7;
const int INF=0x3f3f3f3f;
int N,d1,d2;
int a[maxn],b[maxn],cnt[maxn];
int main(){
    while(scanf("%d%d%d",&N,&d1,&d2)!=EOF){
        for(int i=1;i<=N;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<N;i++){
            b[i]=a[i+1]-a[i];
        }
        memset(cnt,0,sizeof(cnt));
        int num=1;
        a[1]=b[1],cnt[1]=1;
        for(int i=2;i<N;i++){
            if(b[i]==b[i-1]){
                cnt[num]++;
            } else {
                a[++num]=b[i];
                cnt[num]++;
            }
        }
        LL ans=0;
        for(int i=1;i<=num;i++){
            if(i<num&&a[i]==d1&&a[i+1]==d2){
                ans+=1LL*cnt[i]*cnt[i+1];
            }
            if(a[i]==d1){
                ans+=1LL*cnt[i]*(cnt[i]+1)/2;
            }
            if(a[i]==d2){
                ans+=1LL*cnt[i]*(cnt[i]+1)/2;
            }
        }
        if(d1==d2)ans/=2;
        printf("%I64d\n",ans+N);
    }
    return 0;
}

Travelling Salesman Problem

Problem Description

Teacher Mai is in a maze with n rows and m columns. There is a non-negative number in each cell. Teacher Mai wants to walk from the top left corner (1,1) to the bottom right corner (n,m). He can choose one direction and walk to this adjacent cell. However, he can’t go out of the maze, and he can’t visit a cell more than once.

Teacher Mai wants to maximize the sum of numbers in his path. And you need to print this path.

Input

There are multiple test cases.

For each test case, the first line contains two numbers n,m(1≤n,m≤100,n∗m≥2).

In following n lines, each line contains m numbers. The j-th number in the i-th line means the number in the cell (i,j). Every number in the cell is not more than 104.

Output

For each test case, in the first line, you should print the maximum sum.

In the next line you should print a string consisting of “L”,”R”,”U” and “D”, which represents the path you find. If you are in the cell (x,y), “L” means you walk to cell (x,y−1), “R” means you walk to cell (x,y+1), “U” means you walk to cell (x−1,y), “D” means you walk to cell (x+1,y).

Sample Input

3 3
2 3 3
3 3 3
3 3 2

Sample Output

25
RRDLLDRR

思路:因为数全都是非负数,所以肯定是加的越多越好。如果N或者M中有一个是奇数,那么肯定是可以全都走一遍的,那么剩下的就是都是偶数的情况,这种情况稍微复杂点。因为起点是(1,1)1+1是偶数,终点是(N,M)和也是偶数,那么经过的路径上必然偶数比奇数多一个,那么必然是有一个和为奇数的格子是走不到的,所以想办法绕过最小的并且和为奇数的那个格子就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=110;
int a[maxn][maxn],n,m;
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int mn=INF,sum=0,x=-1,y=-1;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                scanf("%d",&a[i][j]);
                if((i+j)%2==1&&mn>a[i][j])
                {
                    mn=a[i][j];
                    x=i;
                    y=j;
                }
                sum+=a[i][j];
            }
        }
        if(n%2){
            printf("%d\n",sum);
            for(int i=0;i<n;i++){
                for(int j=0;j<m-1;j++){
                    if(i%2) printf("L");
                    else printf("R");
                }
                if(i<n-1) printf("D");
            }
            printf("\n");
            continue;
        }

        if(m%2)
        {
            printf("%d\n",sum);
            for(int i=0;i<m;i++){
                for(int j=0;j<n-1;j++){
                    if(i%2) printf("U");
                    else printf("D");
                }
                if(i<m-1) printf("R");
            }
            printf("\n");
            continue;
        }
        printf("%d\n",sum-mn);
        a[x][y]=INF;
        for(int i=0;i<x/2;i++)
        {
            for(int j=0;j<m-1;j++)
                printf("R");
            printf("D");
            for(int j=0;j<m-1;j++)
                printf("L");
            printf("D");
        }
        int step[4][2]={1,0,0,1,-1,0,0,1},tx=x/2*2,ty=0,i=0;
        while(tx!=x/2*2+1||ty!=m-1)
        {
            int gx=tx+step[i][0],gy=ty+step[i][1];
            if(a[gx][gy]==INF)
            {
                printf("R");
                ty+=1;
                continue;
            }
            if(i==0)printf("D");
            else if(i==1)printf("R");
            else if(i==2)printf("U");
            else if(i==3)printf("R");
            tx=gx;
            ty=gy;
            i++;
            i=i%4;
        }
        if(n/2-x/2-1>0) printf("D");
        for(int i=0;i<n/2-x/2-1;i++)
        {
            for(int j=0;j<m-1;j++)
                printf("L");
            printf("D");
            for(int j=0;j<m-1;j++)
                printf("R");
            if(i!=n/2-x/2-1-1)printf("D");
        }
        printf("\n");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值