A. On Segment's Own Points
题目:http://codeforces.com/contest/397/problem/A
大意:求N-1个区间在第一个区间上没有覆盖的长度,所有输入数据均在100以内。
思路:用一个标记数组F[ i ]表示区间[ i-1, i ]的覆盖次数,累计第一个区间上覆盖次数为1 的单位区间就是答案。
Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int f[200], l[200], r[200];
int m = 0;
int main() {
int n; cin>>n;
for (int i=1; i<=n; i++){
cin >> l[i] >> r[i];
for (int j=l[i]+1; j<=r[i]; j++)
f[j] ++;
}
int s = 0;
for (int i=l[1]+1; i<=r[1]; i++){
//cout << i <<' ' << f[i] <<endl;
if (f[i] == 1) s ++;
}
cout <<s << endl;
return 0;
}
题目:http://codeforces.com/contest/397/problem/B
大意:1000个询问,整数N是否能由区间[ Li,Ri]中的整数若干次加得,数据范围在10^9以内。
思路:一个[Li, Ri]中的数可以表示范围[Li,Ri]
俩个[Li, Ri]中的数可以表示范围[2×Li,2×Ri]
... ...
那么K个[Li,Ri]中的数可以表示范围[K×Li,K×Ri]
由此得到算法 : K = N div L // 最少需要K个数相加
判断 K × R >= N 是否成立即可
Ps : K ×R需要用到long long
Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
int n, l, r;
long long k, x, t;
int main(){
int T; cin >> T;
while(T--){
scanf("%d %d %d", &n, &l, &r);
k = n / l;
//cout << k << ' ' << k * r <<endl;
if (k * r >= n) printf("Yes\n");
else printf("No\n");
}
return 0;
}
C. On Number of Decompositions into Multipliers
题目:http://codeforces.com/contest/397/problem/C
大意:给定M,将M重新划分为N个数的乘积,问有多少种分法,N<=500,Ai<=10^9
思路:从质因数的角度考虑,将M看做P1^K1 * P2^K2 * P3^K3 * ... ... *Pm^Km = M,Pi为M的质因数
由于划分是乘法,显然每个Pi之间可看作独立的部分;
那么Ki个Pi划分成N个部分,相当于将Ki个相同的球放入N个不同的盒子,允许空盒,用隔板法可知方案数为C(N+Ki-1,N-1);
将每个Pi的答案累乘就得到最后的答案;
完整的算法为:
预处理组合公式C[A, B] = C[A-1,B] + C[A-1,B-1] ;
把每个Ai质因数分解,用Map存放并累计每个质因数的个数;
最后遍历Map,累乘得到最后的答案
注意考虑分解质因数时排除1的情况,预处理组合公式时可用记忆化搜索优化,数据类型用long long
Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
#define LL long long
#define MOD 1000000007
#define maxn 20000
#define maxm 510
map<int, int> pri;
LL c[maxn][maxm];
void add(int x){
for (int i=2; i*i<=x; i++){
int t = 0;
while (x % i == 0){
t ++;
x /= i;
}
pri[i] += t;
}
if (x > 1) pri[x] ++;
}
LL comb(int a, int b){
if (c[a][b]) return c[a][b];
if (a == b || b == 0) return 1;
return c[a][b] = (comb(a-1,b)+ comb(a-1,b-1))%MOD;
}
int main(){
int n; scanf("%d", &n);
for (int i=1; i<=n; i++){
int x; scanf("%d", &x);
if (x > 1) add(x);
}
LL ans = 1;
for (map<int, int> ::iterator i=pri.begin(); i!=pri.end(); i++){
int m = (*i).second;
//cout << (*i).first << ' ' << m << endl;
//cout << n+m-1 << ' ' << n-1 << ' ' << comb(n+m-1,n-1) <<endl;
ans = (ans * comb(n+m-1, n-1))%MOD;
}
cout << ans <<endl;
return 0;
}
D. On Sum of Fractions
题目:http://codeforces.com/contest/397/problem/D
大意:定义v(i)是不超过i的最大质数,u(i)是严格大于i的最小质数,给定N,求
思路:用Pri[i]表示从质数,Pri[1] = 2,Pri[M] = u(N);
那么Ans = (Pri[2] - Pri[1]) \ (Pri[1] * Pri[2]) + (Pri[3] - Pri[2]) \ (Pri[2] * Pri[3]) + ... ... + (N - Pri[M-1]) \ (Pri[M-1] * Pri[M]) ;
将上式列项,有(Pri[k] - Pri[k-1]) \ (Pri[k-1] * Pri[k]) = 1 \ Pri[k-1] - 1 \ Pri[k] ;
那么1° 若N = u(N)-1,显然Ans = 1 \ Pri[1] - 1 \ Pri[M] = 1 \ 2 - 1 \ u(N);
2° 若N ≠ u(N)-1,那么令 x = (u(N)- v(N)) - (N - v(N)+1)有Ans = 1 \ 2 - 1 \ u(N) - x \ u(N) * v(N);
最后算出分子分母除以gcd约分即可,数据范围需要用到long long
又10^18内的素数分布稠密,可以直接For循环求解u(N)v(N)
Code:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const long long maxn = 1e10;
long long n;
long long p, q;
bool prime(long long x){
for (int i=2; i<=sqrt(x); i++)
if (x % i == 0) return false;
return true;
}
long long lower(long long x){
while (! prime(x))
x --;
return x;
}
long long higher(long long x){
x++;
while (! prime(x))
x ++;
return x;
}
long long gcd(long long a, long long b){
if (a == 0) return b;
if (b == 0) return a;
return gcd(b, a % b);
}
int main(){
int T; cin >> T;
while(T--){
scanf("%d", &n);
p = lower(n);
q = higher(n);
long long m = p*q;
long long x = (q-p)-(n-p+1);
x = m - 2*p - 2*x; m *= 2;
long long k = gcd(x, m);
//cout << p << ' ' << q << ' '<< x << endl;
cout << x/k << '/' << m/k << endl;
}
return 0;
}
小结:
1° Map的用法
Map<int, int> name 第一个键值可以直接访问下标,但不可修改。
遍历Map for (int map<int, int> :: iterator i=name.begin(); i!=name.end();i++)
Map的两个键值访问 (*i).first (*i).second
2°分解质因数
直接从2遍历每次除到底即可,记得考虑最后剩余的除数是否存在。
3。素数分布
10^18内的素数分布稠密,找相邻的素数用for循环暴力查找时间消耗很小。