CSU 1810: Reverse

关键词:逆元、贡献、快速幂

题目:

Description

Bobo has a n digits decimal number D=d 1 d 2…d n (It may have leading zeros).
Let R(i,j) denotes number D with digits between the i-th position and j-th position reversed. That is, R(i,j)=d 1…d i-1 d j d j-1…d i d j+1 d j+2…d n.
Bobo would like to find
modulo (10 9+7).

Input

The input contains at most 30 sets. For each set:
The first line contains an integer n (1≤n≤10 5).
The second line contains n digits d 1 d 2…d n (0≤d i≤9).

Output

For each set, an integer denotes the result.

Sample Input

2
12
3
012
10
0123456789

Sample Output

45
369
733424314

这个题目给的是5秒,估计θ(n log n)的算法也是可以过的。
不过很多人都是用θ(n)的算法过的,我也是的。
假设某个数字左边有k个数字,右边有s个,那么k+s=n-1
假设mik=10^k,mis=10^s,那么这个数字的贡献是(k(k+1)/2+s(s+1)/2)*mis+(mis*10-1)/9+(mik*10-1)/9
m9是9的逆元,m10是10的逆元,这2个逆元是可以手算出来的,当然,编程算出来也很快。
有了m9就只有乘法没有除法了,有了m10,mik和mis都可以迭代着计算,而不需要快速幂了。
main函数里面唯一一次调用快速幂函数mi是初始化mis = mi(n - 1)
这样,只需要扫描一遍数组就可以得到答案了。
其实字符数组是不需要的,可以一个个字符输入,不存,直接计算。

代码:

#include<iostream>
#include<string.h>
using namespace std;

int mod = 1000000007, m9 = 111111112, m10 = 700000005;
long long n, mik, mis;
char c[100001];

long long mi(int k)
{
	if (k == 0)return 1;
	long long s = mi(k / 2);
	s = s*s % mod;
	if (k % 2)s *= 10;
	return s%mod;
}

int main()
{
	while (cin >> n)
	{
		scanf("%s", c);
		mik = 1, mis = mi(n - 1);
		long long s = 0;
		for (long long i = 0; i < n; i++)
		{
		long long s1 = (mis * 10 - 1) *m9 %mod *(mik * 10 % mod - 1) % mod *m9 %mod;
			s1 += (i*(i + 1) / 2 + (n - 1 - i)*(n - i) / 2)*mis % mod;
			s = (s + (c[i] - '0')*s1) % mod;
			mik = mik * 10 % mod;
			mis = mis * m10 % mod;
		}
		cout << s << endl;
	}
	return 0;
}

你可能感兴趣的:(快速幂,逆元)