比赛链接:http://codeforces.com/contest/702
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <vector> 7 #include <cmath> 8 #include <ctime> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 typedef long long LL; 14 typedef pair <int, int> P; 15 const int N = 1e5 + 5; 16 int a[N]; 17 18 int main() 19 { 20 int n; 21 scanf("%d" , &n); 22 int temp = 1 , res = 1; 23 scanf("%d" , a + 1); 24 for(int i = 2 ; i <= n ; ++i) { 25 scanf("%d" , a + i); 26 if(a[i] > a[i - 1]) { 27 temp++; 28 res = max(res, temp); 29 } 30 else { 31 temp = 1; 32 } 33 } 34 printf("%d " , res); 35 return 0; 36 }
B题求有多少对数的和等于2的幂(即a[i] + a[j] = 2的幂)。
[map乱搞] 先用map存a[i]出现的次数。因为2的幂的个数也就30多个,那我们可以for一遍a数组,然后枚举2的幂。
统计mp[2的幂 - a[i]]的大小。要是2的幂-a[i]等于a[i],统计的时候减一就好了。
最后答案除以2,因为每对重复统计了两次。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <vector> 7 #include <cmath> 8 #include <ctime> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 typedef __int64 LL; 14 typedef pair <int, int> P; 15 const int N = 1e5 + 5; 16 map <LL , LL> mp; 17 LL num[35]; 18 LL a[N]; 19 20 int main() 21 { 22 mp.clear(); 23 num[0] = 1; 24 for(int i = 1 ; i <= 33 ; ++i) { 25 num[i] = num[i - 1] * 2; 26 } 27 int n; 28 scanf("%d" , &n); 29 for(int i = 1 ; i <= n ; ++i) { 30 scanf("%lld" , a + i); 31 mp[a[i]]++; 32 } 33 LL res = 0; 34 for(int i = 1 ; i <= n ; ++i) { 35 for(int j = 1 ; j <= 33 ; j++) { 36 if(num[j] < a[i]) 37 continue; 38 res += mp[num[j] - a[i]]; 39 if(num[j] == 2 * a[i]) 40 res--; 41 } 42 } 43 printf("%lld " , res / 2); 44 return 0; 45 }
C题题意是给你n个城市和m个塔的坐标,问你塔的信号半径最少是多少能够覆盖所有的城市。
[二分答案] 二分半径,每次二分一下 然后判断半径的可行性,可行性的话for一遍就好了。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <vector> 7 #include <cmath> 8 #include <ctime> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 typedef __int64 LL; 14 typedef pair <int, int> P; 15 const int N = 1e5 + 5; 16 LL a[N] , b[N]; 17 int n , m; 18 19 bool check(LL r) { 20 int index = 1 , cnt = 0; 21 for(int i = 1 ; i <= n , index <= m; ++i) { 22 if(a[i] >= b[index] - r && a[i] <= b[index] + r) { 23 cnt++; 24 continue; 25 } 26 else { 27 index++; 28 i--; 29 } 30 } 31 if(cnt >= n) 32 return true; 33 return false; 34 } 35 36 int main() 37 { 38 scanf("%d %d", &n , &m); 39 for(int i = 1 ; i <= n ; ++i) { 40 scanf("%lld" , a + i); 41 } 42 for(int i = 1 ; i <= m ; ++i) { 43 scanf("%lld" , b + i); 44 } 45 LL l = 0 , r = 2*1e9+1; 46 while(l < r) { 47 LL mid = (l + r) / 2; 48 if(check(mid)) { 49 r = mid; 50 } 51 else { 52 l = mid + 1; 53 } 54 } 55 printf("%lld " , r); 56 return 0; 57 }
D题条件是:d代表路程长度,k代表车子每行驶k长度就会坏,a代表车行驶单位长度的时间,b代表人走路单位长度的时间,t代表坏的车修好时间。
车好像一开始没坏,问你最少需要多少时间能到终点。
[分类讨论] 一开始肯定要开车。后来我是比较车的平均速度(k/(k*a+t))和人的平均速度(1/b)。
要是人的速度大于等于车的速度,那走路到终点就好了。
不然的话就开车,但是开车开了k的整数倍,剩下路程(d')要是不到k的话,那讨论剩下的路 人和车谁话的时间最少(min(d'*a+k, d'*b))。
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <vector> 7 #include <cmath> 8 #include <ctime> 9 #include <list> 10 #include <set> 11 #include <map> 12 using namespace std; 13 typedef __int64 LL; 14 typedef pair <int, int> P; 15 const int N = 1e5 + 5; 16 17 int main() 18 { 19 LL d , k , a , b , t , res = 0; 20 cin >> d >> k >> a >> b >> t; 21 LL ans = d; 22 d -= k; 23 res = k*a; 24 if(d <= 0) { //一开始k < d的情况 25 cout << a * ans << endl; 26 return 0; 27 } 28 double car = k*1.0 / (a*k + t) , peo = 1.0 / b; //车和人的速度 29 if(peo >= car) { //人的速度大于等于车的速度 30 res += d * b; 31 cout << res << endl; 32 return 0; 33 } 34 LL temp = d; 35 d -= d / k * k; //车后来开了k的整数倍 36 res += temp / k * (k*a + t); 37 if(d > 0) { //剩下的路 车和人 取最小的时间 38 LL temp1 = t + d * a , temp2 = d * b; 39 res += min(temp1 , temp2); 40 } 41 cout << res << endl; 42 return 0; 43 }
E. Analysis of Pathes in Functional Graph
E题题意是有n个点(编号0 ~ n - 1),n条单向边,i和a[i]相连并指向a[i],然后给你每条边的权值。
问你从每个点出发,走k条边,走的路径权值和是多少,还有求其中最小的边是多少。
[倍增法] n条边 所以成环,单向 所以每条路径是唯一的。 可以想象成每个数开头之后的都是循环下去的数组。
可以用倍增法 类似RMQ的做法解,先预处理一下,par[i][j]表示从i点开始2^i后的点的编号,sum[i][j]表示i点开始2^j条边的路径权值和,min[i][j]表示i点开始2^j条边中最小的边权。
查询的时候利用k的二进制性质就行了,也是倍增。
1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio> 7 #include <vector> 8 #include <cmath> 9 #include <ctime> 10 #include <list> 11 #include <set> 12 #include <map> 13 using namespace std; 14 typedef __int64 LL; 15 typedef pair <int, int> P; 16 const int N = 1e5 + 5; 17 int par[N][35]; 18 LL min_val[N][35]; 19 LL sum[N][35]; 20 21 void init(int n) { 22 for(int k = 1; k < 34; ++k) { 23 for(int i = 0; i < n; ++i) { 24 par[i][k] = par[par[i][k - 1]][k - 1]; 25 min_val[i][k] = min(min_val[i][k - 1], min_val[par[i][k - 1]][k - 1]); 26 sum[i][k] = sum[i][k - 1] + sum[par[i][k - 1]][k - 1]; 27 } 28 } 29 } 30 31 void solve(int root, LL x) { 32 LL res_min = 1e8 + 1, res_sum = 0; 33 for(int k = 0; k < 34; ++k) { 34 if(x & (1LL << k)) { 35 res_sum += sum[root][k]; 36 res_min = min(res_min, min_val[root][k]); 37 root = par[root][k]; 38 } 39 } 40 printf("%lld %lld ", res_sum, res_min); 41 } 42 43 int main() 44 { 45 int n; 46 LL m; 47 scanf("%d %lld", &n, &m); 48 for(int i = 0; i < n; ++i) 49 scanf("%d", &par[i][0]); 50 for(int i = 0; i < n; ++i) { 51 scanf("%lld", &min_val[i][0]); 52 sum[i][0] = min_val[i][0]; 53 } 54 init(n); 55 for(int i = 0; i < n; ++i) { 56 solve(i, m); 57 } 58 return 0; 59 }
F题不会