Description
Input
2
Output
2Hint1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cases.
Sample Input
2
Sample Output
2
Hint
1. For N = 2, S(1) = S(2) = 1. 2. The input file consists of multiple test cases.
PS:据说是2013的多校第9场的题,简直烧脑子,至今写这篇题解仍旧没有绕过来一个点,过阵子再回来看看吧;
题目大意:给你一个N , 求S(1)+ S(2) +...+S(n) 的组合数 , 其中S(K)代表可以把N拆分为K个数字 的情况数。 特别绕脑子;
举例分析:
1.当N=1 , S(1) = 1 , 因为N=1可以拆成1这一个数字 , 所以答案是 1
2.当N=2 . S(1) = 1 ,因为N=2,拆成1个数字,还是2 ,一种情况; S(2) 是代表可以拆分为2个数字, 那边是 1 和 1 一种情况, 所以答案是 2
3.当N=3,S(1) = 1 ; S(2) = (1+2) || (2+1) ; S(3) = 3 ; 所以答案是 1 + 2 + 1 = 4 ;
4.当N=4, S(1) = 1 ; S(2) = (2+2)||(1+3)||(3+1) ; s(3) = (1+1+2)||(1+2+1)||(2+1+1) ; S(4) = 4 ; 所以答案是 1+3+3+1 = 8 ;
推规律发现 , find的答案就是 2^(n-1) ; 但是题中的N特别大, 所以就得考虑如何去化简这个n;
这里首先知道 a^b%mod 可以用快速幂解决, 那么 a^n%mod , 且题中mod是一个质数, 所以可以用费马小定理去解决;
费马小定理:a^(p-1)%p = 1 (这里的p就是mod,且p是一个质数)
化简: a^n%p = a^(n%(p-1))%p 所以答案就是求 n % (p-1) , 随后字符串读入然后不断对新生成的n % p-1 即可 ;
对如上进行推导: 首先对于一个整数n可以做如此拆分: n = k(p-1)+n%(p-1) 其中k为系数,p为去摸数
那么对于本题 a^n%p = a^(k(p-1)+n%(p-1))%p ----> a^(k*(p-1))%p * a^(n%(p-1))%p , 前者就是费马小定理,答案为1,系数k不影响
所以推出 化简所事;
本题告一段落QAQ
AC代码:
#include <iostream>
#include <cstdio>
#define ll long long
#define mod 1000000007
using namespace std;
ll quick(ll a , ll b)
{
ll res = 1 ;
a = a % mod ;
while(b)
{
if(b&1) res = res * a %mod ;
b>>=1;
a = a * a %mod ;
}
return res ;
}
int main()
{
char s[500000] ;
while(scanf("%s",s)!=EOF)
{
ll n = 0 ;
for(int i = 0 ; s[i] ; i++)
n = n*10 + (s[i]-'0') , n%=mod-1;
if(!n) printf("1\n");
else cout<<quick(2,n-1)<<endl;
}
return 0;
}