Noobs Round #2 (Div. 4) by Rudro25--E. Password(DP)

You are given a string which is the hint of a password. Given string only consist of character '1' to '9' and '-'.You can replace '-' by any digit from '1' to '9'.Find the number of ways to make a password by replacing all '-' characters to some digit, such that the digits of the password are in non-decreasing order.

If it is impossible to make the digits of the string in non-decreasing order, print "0" otherwise since the answer can be very large, print the answer modulo 10^9+7.

The sequence a is called non-decreasing if a1≤a2≤⋯≤an holds, where n is the length of the sequence.

Input

The first line contains an integer t (1≤t≤10^2) −− the number of test cases in the input.

Then t test cases follow.

The first line of the test case contains one integer n (1≤n≤10^5).

The second line of the test case contains a string s of n characters, consisting only '1' to '9' and '-'.

It is guaranteed that the sum of the values of n for all test cases in the input does not exceed 10^5.

Output

For each test case, If it is impossible to make the digits of the string in non-decreasing order, print "0" otherwise print the number of ways modulo 109+7

input

5
5
1---2
3
3-4
7
2--43-4
8
1---23-4
1
-

output

4
2
0
8
9

Note

In the first test, we have four ways to fill '-' characters 111, 112, 122, 222.

In the second test, we have two ways to fill the '-' character, 3 or 4.

In the third test, it is impossible to convert this into a valid string.

题意:给定长度为n的字符串,'-'可以是1~9,问构造整个序列数值不递减的方案数mod(1e9+7)。

解析:首先判断无解的情况就是原始序列中数字已经出现非递减的情况,输出0即可。

对于有解情况,我们可以单独取出每一段'-'的区间考虑,那么答案肯定就是每一段方案数相乘。对于每一段,我们可以得知取值肯定是[L,R],L是a[l]-'0',R是a[r]-'0'。

我们可以考虑dp[ i ][ j ]是长度为 i ,最后一位是数字 j 的方案数,那么对于 i j,方案数就是 dp[i-1][L~j]的总和。

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5,mod=1e9+7;
typedef pair<int,int> PII;
char a[N];
void solve()
{
    int n,mx=0;//mx表示当前最大出现数字
    scanf("%d%s",&n,a+1);
    for(int i=1;i<=n;i++)
    {
        if(a[i]!='-')//数字
        {
            if(a[i]-'0'<mx)//如果小于mx,表示不合法输出0即可
            {
                printf("0\n");
                return;
            }
            mx=max(mx,a[i]-'0');
        }
    }
    vector<PII> v;//存储每一个'-'连续区间
    int l=-1,r;
    a[0]='1',a[n+1]='9';//便于考虑边界情况
    for(int i=1;i<=n+1;i++)
    {
        if(a[i]=='-'&&l==-1) l=i,r=i;
        else if(a[i]=='-') r=i;
        else
        {
            if(l!=-1) v.push_back({l,r});
            l=-1;
        }
    }
    int sum=1;
    for(int i=0;i<v.size();i++)
    {
        int l=v[i].first;
        int r=v[i].second;
        int len=r-l+1;//区间长度
        l=a[l-1]-'0';//下界值
        r=a[r+1]-'0';//上界值
        vector<vector<int>> dp;
        dp.resize(len+5);
        for(int j=0;j<=len;j++) dp[j].resize(15,0);
        for(int j=l;j<=r;j++) dp[1][j]=1;//前i个位置最后一位是j
        for(int j=1;j<=len;j++)
        {
            for(int k=l;k<=r;k++)
            {
                for(int h=l;h<=k;h++)
                {
                    dp[j][k]=(dp[j][k]+dp[j-1][h])%mod;
                }
            }
        }
        int res=0;//当前该区间的方案数
        for(int j=l;j<=r;j++) res=(res+dp[len][j])%mod;//长度为len,以[l,r]结尾的方案数
        sum=sum*res%mod;//每个区间方案数相乘
    }
    printf("%d\n",sum);
}
int main()
{
    int t=1;
    scanf("%d",&t);
    while(t--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值