每日一题之 hiho226周 Ctrl-C Ctrl-V

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014046022/article/details/83515307

描述
Yor are bored. So you open a notepad and keep pressing letter ‘A’ to type a lot of 'A’s into the text area.

Suddenly an idea come out. If you can do the following 4 kinds of operations N times, how many 'A’s you can type into the text area?

  • A: Type a letter A into the text area

  • Ctrl-A: Select all the letters in the text area

  • Ctrl-C: Copy the selected letters into clipboard

  • Ctrl-V: Paste the letters from clipboard into the text area

Assume N=7 you can get 9 'A’s by doing following operations: A, A, A, Ctrl-A, Ctrl-C, Ctrl-V, Ctrl-V.

输入
An integer N. (1 <= N <= 1000000000)

输出
The maximum number of 'A’s you can type into the text area. Note the answer may be very large so output the answer modulo 1000000007.

样例输入
7
样例输出
9

题意:

给n个操作,问最多能组成多少个A

思路:

借用官方的解答思路
首先,对于最优方案,Ctrl-A + Ctrl-C + 若干个Ctrl-V一定是连在一起的。

例如 Ctrl-A + A + Ctrl-C + Ctrl-V,一定不如把A放在Ctrl-A之前,即: A + Ctrl-A + Ctrl-C + Ctrl-V

Ctrl-A + Ctrl-C + A + Ctrl-V 一定不如 A + Ctrl-A + Ctrl-C + Ctrl-V。

我们用f[i]表示i个操作最多能输出多少个A。对于最优解,最后一个操作一定是A或者Ctrl-V。

如果最后一个操作是A,则f[i] = f[i-1] + 1;如果最后一个操作是Ctrl-V,我们假设最后一共有连续K个Ctrl-V,则f[i] = f[i-2-K] * (K+1)。

于是我们可以得到一个O(N^2)的DP算法。

当然本题数据范围很大,O(N^2)的DP没办法通过所有的数据。不过我们可以用这个算法得到前若干项的值。例如N=1…25的答案如下:

1 1
2 2
3 3
4 4
5 5
6 6
7 9
8 12
9 16
10 20
11 27
12 36
13 48
14 64
15 81
16 108
17 144
18 192
19 256
20 324
21 432
22 576
23 768
24 1024
25 1296
可以看出,对于N >= 16,f[N] = f[N - 5] * 4。换句话说,当N足够大的时候,最优的策略就是用Ctrl-A + Ctrl-C + Ctrl-V + Ctrl-V + Ctrl-V 5个操作把长度变成4倍。

于是f[N] = f[x] * 4^K, 其中11 <= x <= 15 且 N = x + 5K。其中4^K需要用快速幂实现。

需要注意的是,直接用int可能有些取模不注意会爆掉,需要换成long long

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int mod = 1e9+7;

typedef long long llint;

llint dp[20];

void init() {

	for (llint i = 1; i <= 6; ++i)
		dp[i] = i;

	dp[7] = 9;
	dp[8] = 12;
	dp[9] = 16;
	dp[10] = 20;
	dp[11] = 27;
	dp[12] = 36;
	dp[13] = 48;
	dp[14] = 64;
	dp[15] = 81;

}

llint quickPow(llint x, llint n)
{
    llint res = 1;
    while(n) {
        if (n&1) res = (res * x)%mod;
        x = (x * x)%mod;
        n >>= 1;
    }

    return res;
}

void solve(llint n) {

	init();
	if (n <= 15) {
		cout << dp[n]<< endl;
		return;
	}
	llint k = 0;
	llint x = 0;
	for (llint i = 11; i <= 15; ++i) {
		if ((n - i)%5 == 0) {
			k = (n-i)/5;
			x = i;
			break;
		}
	}

	llint res = (dp[x]*quickPow(4,k))%mod;

	cout << res << endl;
}

int main() {

	llint n;
	cin >> n;
	solve(n);

	return 0;

}

猜你喜欢

转载自blog.csdn.net/u014046022/article/details/83515307