首页 > 代码库 > Codeforces Round #232 (Div. 1)
Codeforces Round #232 (Div. 1)
这次运气比较好,做出两题。本来是冲着第3题可以cdq分治做的,却没想出来,明天再想好了。
A. On Number of Decompositions into Multipliers
题意:n个数a1,a2, a3...an求n个数相乘与a1*a2*a3*a4...an相等的排列个数。
分析:首先应该对ai分解质因数,求出所有ai中质因数及个数,枚举排列中每个数包含的质因数个数,例如质因数qi,有ni个,相应的排列中数包含质因数qi个数设为x1,x2,....xn, x1+x2+x3..+xn = ni , 那么对于qi共有C(ni+n-1, n-1)种情况。简单来说就是将ni分成n部分,这样想:有ni个球,需要分成n部分,也就是在n个球中插入n-1根木棍,这样分成n部分就相当于ni+n-1中选n-1个位置。最后把所有质因子可能的划分情况相乘起来就行了。
注意:分解质因数最后一个质因数可能很大!
代码:
1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define bug(x) printf("Line %d : >>>>>>>\n", (x)); 4 #define pb push_back 5 6 using namespace std; 7 typedef long long LL; 8 typedef map<int, int> Mps; 9 const int M = (int)1e9+7;10 const int maxn = 555;11 const int maxm = (int)1e5 + 100;12 LL inv[maxn];13 int a[maxn];14 Mps Div;15 vector<int> dv;16 17 LL powmod(LL a, LL b) {18 LL res = 1;19 while(b) {20 if(b&1)21 res = (res*a)%M;22 b >>= 1;23 a = (a*a)%M;24 }25 return res;26 }27 void getInv(int n) {28 for(int i = 1; i < n; i++) {29 inv[i] = powmod(i, M-2);30 }31 }32 void getDiv(int x) {33 int m = (int)sqrt(x+.5);34 for(int i = 2; i <= m; i++) {35 if(x%i == 0) {36 if(Div[i] == 0)37 dv.pb(i);38 while(x%i == 0) {39 Div[i]++;40 x/=i;41 }42 }43 }44 if(x > 1) {45 if(Div[x] == 0)46 dv.pb(x);47 Div[x]++;48 }49 }50 LL nCr(LL n, LL m) {51 LL res = 1;52 for(int i = 0; i < m; i++) {53 res = res*(n-i)%M*inv[i+1]%M;54 if(res < 0)55 res += M;56 }57 return (res + M)%M;58 }59 int main() {60 61 getInv(maxn);62 int n;63 scanf("%d", &n);64 for(int i = 1; i <= n; i++) {65 scanf("%d", a+i);66 getDiv(a[i]);67 }68 LL ans = 1;69 for(int i = 0; i < (int)dv.size(); i++) {70 int x = dv[i];71 ans = ans*nCr(Div[x]+n-1, n-1)%M;72 }73 cout<<ans<<endl;74 return 0;75 }
B. On Sum of Fractions
题意:给定n, u(i)表示不超过i的最大质数, v(i)表示大于i的最小质数。求对于所有的2<= i <= n , sum{1/(u(i)*v(i)}, 最简分式结果。
分析:
列出n的前几个数的1/u(i)*v(i),发现对于两个相邻素数pi, pi+1间的数i, 1/u(i)*v(i)结果是一样的。也就是说 对于 pi <= x < pi+1, sum{1/u(x)v(x)},化简后就是, 1/u(x)-1/v(x), 得到这个结论后,每次找到大于n的一个素数pi+1,结果就变成两部分, x < pi, 和 pi <= x < n, 第一部分化简就是1/2-1/pi ,第二部分:n-pi+1/(pi*pi+1), 两者之和合并一下就会得到一个表达式:2*(n+1)-2*(pi+pi+1)-pi*pi+1/(2*pi*pi+1)。求质数,用Miller-Rabin法判断前后两个质数就可以了。
代码:
1 #include <bits/stdc++.h> 2 #define in freopen("solve_in.txt", "r", stdin); 3 #define bug(x) printf("Line %d : >>>>>>>\n", (x)); 4 #define pb push_back 5 6 using namespace std; 7 typedef pair<int, int> PII; 8 typedef long long LL; 9 typedef map<int, int> Mps;10 11 LL powmod(LL a, LL b, LL c) {12 LL res = 1;13 while(b) {14 if(b&1) res = res*a%c;15 b >>= 1;16 a = (a*a)%c;17 }18 return res;19 }20 bool test(int n, int a, int d) {21 if(n == 2)return true;22 if(n == a) return true;23 if((n&1) == 0) return false;24 while(!(d&1)) d >>= 1;25 int t = powmod(a, d, n);26 while((d != n-1) && (t != 1) && (t != n-1)) {27 t = (LL)t*t%n;28 d <<= 1;29 }30 return (t == n-1) || (d&1) == 1;31 32 }33 bool isPrime(int n) {34 if(n < 2) return false;35 int a[] = {2, 3, 61};36 for(int i = 0; i <= 2; i++) if(!test(n, a[i], n-1)) return false;37 return true;38 }39 pair<LL, LL> getPrime(LL n) {40 LL x = n;41 x++;42 PII ans;43 while(1) {44 if(isPrime(x)) {45 ans.first = x;46 break;47 }48 x++;49 }50 x = n;51 while(1) {52 if(isPrime(x)) {53 ans.second = x;54 break;55 }56 x--;57 }58 return ans;59 }60 LL getGcd(LL a, LL b) {61 return !b ? a : getGcd(b, a%b);62 }63 int main() {64 65 int T;66 int n;67 for(int t = scanf("%d", &T); t <= T; t++) {68 scanf("%d", &n);69 if(n == 2) {70 puts("1/6");71 } else {72 PII u = getPrime(n);73 LL x = u.first, y = u.second;74 LL a = 2*(n+1)-2*(x+y)+x*y;75 LL b = 2*x*y;76 LL c = getGcd(a, b);77 printf("%I64d/%I64d\n", a/c, b/c);78 }79 }80 return 0;81 }
C. On Changing Tree
题意:
Codeforces Round #232 (Div. 1)