标签:要求 inpu 问题 its 快速幂取模 优化 ons none 图片
1 2 3 4Sample Output
2 2 6 12
解题思路:
本题是一个数学问题,串的每一位不是0就是1,给出一个数字n为串的长度,要求计算这个长度的本原串数量。
由于串的每一位都是0或1,所以n长度下最多有n^2个不同的串。我们用ans[n]表示当前长度下的本原串数量,若想获得本原串数量,可以用当前串的总数减去不是本原串的数量。当n不等于1时,全由1或全由0组成的串肯定不是本源串。所以当前ans[n] = 2^n - 2,回想题中对本原串的定义,非本源串是由某一个长度的本原串重复数次得到的,我们设n的因子为m,则m长度的本原串重复n / m 次一定可以得到n长度的非本原串,且n/ m也为n的因子,长度为n / m的本原串重复m次也一定可以得到长度为n的非本原串,那么我们只需找到当前串长度的所有因子长度的本原串数量即可找到其余所有非本原串数量。
由于n较大所以使用快速幂
快速幂思想:求2^11,11的二进制位1011,11 = 1*2^3 + 0*2^2 + 1*2^1 + 1*2^0,所以可以将2^11转化为2^(2^0) * 2^(2^1) * 2(2^3)。将原先的11次 O(n)优化为了3次O(logn),本题要求取模,又因为积的取余等于取余的积的取余,我们可以直接在快速幂的过程中取模以得到取模后的答案。
快速幂取模:
LL power(int a, int b, int mod){ //快速幂 LL ans = 1; while(b){ if(b & 1){ //从b的二进制末位开始判断 ans = ans * a % mod; //如果为1更新取模后的答案 } a = a * a % mod; //更新底数取模 b >>= 1; //b右移一位 } return ans; }
AC代码
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 const int maxn = 100000005; 5 int ans[maxn]; 6 LL power(int a, int b, int mod){ //快速幂 7 LL ans = 1; 8 while(b){ 9 if(b & 1){ //从b的二进制末位开始判断 10 ans = ans * a % mod; //如果为1更新取模后的答案 11 } 12 a = a * a % mod; //更新底数取模 13 b >>= 1; //b右移一位 14 } 15 return ans; 16 } 17 LL clt(int n){ //传入当前长度 18 if(ans[n] != 0) //如果ans[n]不为0证明之前的计算已经计算完成当前长度的本原串数量直接返回答案 19 return ans[n]; 20 ans[n] = power(2, n, 2008) - 2; //减去全0与全1 21 for(int i = 2; i * i <= n; i++){ //寻找因子 22 if(n % i == 0){ //i为因子 23 ans[n] = (ans[n] - clt(i) + 2008) % 2008; 24 //当前数量减去因子长度的本原串数量,由于做减运算可能出现负数所以加上取模数再取模 25 if(i * i != n) 26 ans[n] = (ans[n] - clt(n / i) + 2008) % 2008; 27 //随便计算另一个因子 28 } 29 } 30 return ans[n]; 31 } 32 int main() 33 { 34 ans[0] = 0, ans[1] = 2, ans[2] = 2; //初始化长度为0 1 2时的本原串数量 35 int n; 36 //clt(100000005);本题不能打表,会超时 37 while(scanf("%d", &n) != EOF){ 38 if(n > 2) //n大于2进行运算 39 ans[n] = clt(n); 40 printf("%d\n", ans[n]); 41 } 42 return 0; 43 }
标签:要求 inpu 问题 its 快速幂取模 优化 ons none 图片
原文地址:https://www.cnblogs.com/suvvm/p/9998801.html