Codeforces 464C Substitutes in Number(大数取模思想)

C. Substitutes in Number
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Andrew and Eugene are playing a game. Initially, Andrew has string s, consisting of digits. Eugene sends Andrew multiple queries of type “di → ti”, that means “replace all digits di in string s with substrings equal to ti”. For example, if s = 123123, then query “2 → 00” transforms s to 10031003, and query "3 → " (“replace 3 by an empty string”) transforms it to s = 1212. After all the queries Eugene asks Andrew to find the remainder after division of number with decimal representation equal to s by 1000000007 (109 + 7). When you represent s as a decimal number, please ignore the leading zeroes; also if s is an empty string, then it’s assumed that the number equals to zero.

Andrew got tired of processing Eugene’s requests manually and he asked you to write a program for that. Help him!

Input
The first line contains string s (1 ≤ |s| ≤ 105), consisting of digits — the string before processing all the requests.

The second line contains a single integer n (0 ≤ n ≤ 105) — the number of queries.

The next n lines contain the descriptions of the queries. The i-th query is described by string “di->ti”, where di is exactly one digit (from 0 to 9), ti is a string consisting of digits (ti can be an empty string). The sum of lengths of ti for all queries doesn’t exceed 105. The queries are written in the order in which they need to be performed.

Output
Print a single integer — remainder of division of the resulting number by 1000000007 (109 + 7).

Examples
inputCopy
123123
1
2->00
outputCopy
10031003
inputCopy
123123
1
3->
outputCopy
1212
inputCopy
222
2
2->0
0->7
outputCopy
777
inputCopy
1000000008
0
outputCopy
1

题意

很有趣的一道题,一开始给你一个数,然后接下去有n次操作,每次操作可以选择一位数字将其替换成箭头后面的数,经过n次操作的这个数最后对1000000007取余

思路

我们先来看一下对一个大数我们是如何对他取模的

    long long sum=0;
    for(int i=0;i<len;i++)
    {
        sum*=10;
        sum+=num[i];
        sum%=mod;
    }

因为我们处理的是10进制,所以对于每个10进制数每次所能提供的位数都是10,所以每次操作的第一次都是乘以10,然后再自己加上自己
那么我们可以根据这个思想来处理题目,我们可以把操作倒着来,目的是处理出 0 ∼ 9 0\sim 9 09中每个数字所能提供的价值位数,来看个例子
100 100 100 0 − > 313 0->313 0>313 3 − > 12 3->12 3>12
一开始 0 ∼ 9 0\sim 9 09每个数的价值都是他本身,所能提供的位数都是 10 10 10
然后我们开始处理 3 3 3所对应的价值位数 3 − > 12 3->12 3>12 1 1 1还是对应 1 1 1 2 2 2还是对应 2 2 2,所以 3 − > 12 3->12 3>12,但是 3 3 3所提供的位数不再是 10 10 10,而是 1 1 1 2 2 2所提供的位数的乘积也就是 3 − > 12 ∣ 100 3->12\mid 100 3>12100然后我们来操作 0 − > 313 0->313 0>313
同上 0 − > 12112 0->12112 0>12112,且 0 0 0所能提供的位数为各位所提供的位数的乘积 0 − > 12112 ∣ 100000 0->12112\mid 100000 0>12112100000,替换的过程就是大数取模的过程

	sum=0;
	for(int i=0;i<len;i++)
	{
		sum*=wei[];
		sum+=v[];
		sum%=mod;
	}
	/*
	sum=0;      乘上3所提供的位数100
	sum=12;     加上3所提供的价值12
	sum=120;    乘上1所提供的位数10
	sum=121;    加上1所提供的价值1
	sum=12100;  乘上3所提供的位数100
	sum=12112;  加上3所提供的价值12
	*/

所以最后我们的得到的是 0 ∼ 9 0\sim 9 09 10个数字所能提供的价值和位数,我们每次只要维护这两个数组即可,根据取模的性质,每个数所提供的价值是可以取模的,同样的位数也是可以取模的
然后最后再对初串处理一遍即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const long long mod=1e9+7;
struct node
{
    int id;
    string s;
}a[100005];
char str[100005];
long long val[10],wei[10];
int main()
{
    scanf("%s",str);
    int n;
    scanf("%d",&n);
    char temp[100005];
    for(int i=0;i<n;i++)
    {
        scanf("%1d->",&a[i].id);
        gets(temp);
        a[i].s=temp;
    }
    for(int i=0;i<10;i++)
        val[i]=i,wei[i]=10;
    for(int i=n-1;i>=0;i--)
    {
        int len=a[i].s.length();
        if(len==0)
        {
            val[a[i].id]=0;
            wei[a[i].id]=1;
        }
        long long sum1=0,sum2=1;
        for(int j=0;j<len;j++)
        {
            sum1*=wei[a[i].s[j]-'0'];
            sum1+=val[a[i].s[j]-'0'];
            sum1%=mod;
            sum2*=wei[a[i].s[j]-'0'];
            sum2%=mod;
        }
        val[a[i].id]=sum1;
        wei[a[i].id]=sum2;
    }
    long long ans=0;
    int len=strlen(str);
    for(int i=0;i<len;i++)
    {
        ans*=wei[str[i]-'0'];
        ans+=val[str[i]-'0'];
        ans%=mod;
    }
    printf("%lld\n",ans);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值