CFEDU 15
- [A. Maximum Increase](http://codeforces.com/contest/702/problem/A)
- [B. Powers of Two](http://codeforces.com/contest/702/problem/B)
- [C. Cellular Network](http://codeforces.com/contest/702/problem/C)
- [D. Road to Post Office](http://codeforces.com/contest/702/problem/D)
- [E. Analysis of Pathes in Functional Graph](http://codeforces.com/contest/702/problem/E)
A. Maximum Increase
思路
注意是连续, 所以我们可以直接用尺取法。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100010];
int ans = 0;
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
int l = 1;
int r = 1;
while(r <= n)
{
while(a[r+1] > a[r])
{
r++;
}
ans = max(ans, r - l + 1);
r++;
l = r;
}
cout << ans << endl;
return 0;
}
dalao
直接遍历一边即可。
const int N = 200000;
int n, ar[N];
int len, ans;
int main(){
ios_base::sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> ar[i];
if (ar[i] > ar[i - 1])
len++;
else
len = 1;
ans = max(ans, len);
}
cout << ans << endl;
return 0;
}
B. Powers of Two
思路
如果考虑枚举两个数的话
O
(
N
2
)
O(N^2)
O(N2)
不妨考虑换序枚举。
因为
2
x
2^x
2x在
1
0
9
10^9
109内x最多为30, 可以枚举x。
那么, 我们只需要在枚举一个数
a
i
a_i
ai,
a
j
a_j
aj就可以
2
x
−
a
i
2^x - a_i
2x−ai表示。
又因为需要
i
<
j
i \lt j
i<j,所以我们只需要从后往前遍历, 用一个map记录出现过的数即可。
代码
#include<bits/stdc++.h>
using namespace std;
int n;
int a[100010];
map<int, int>mp;
long long ans = 0;
int ksm(int a, int b)
{
int res = 1;
while(b)
{
if(b & 1)
res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
for(int x = 1; x <= 30; x++)
{
int now = ksm(2, x);
mp.clear();
for(int i = n; i >= 1; i--)
{
//cout << now << " " << a[i] << endl;
if(now < a[i])
{
mp[a[i]]++;
continue;
}
//cout << st.count(now - a[i]) << endl;
ans += mp[now-a[i]];
mp[a[i]]++;
}
/*for(int i = 1; i <= n; i++)
{
cout << st.count(a[i]) << endl;
}*/
}
//st.insert(1);
// cout << st.count(1) << endl;
cout << ans << endl;
return 0;
}
dalao
直接正序枚举即可。
统计一下次数, 相乘。
最后答案除以2;
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
typedef long long ll;
const int Maxb = 31;
int n;
map <int, int> M;
ll res;
int main()
{
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int a; scanf("%d", &a);
M[a]++;
}
for (int i = 0; i < Maxb; i++)
for (map <int, int>::iterator it = M.begin(); it != M.end(); it++)
if (it->first <= (1 << i)) {
int nd = (1 << i) - it->first;
if (nd == it->first) res += ll(it->second) * (it->second - 1);
else if (M.find(nd) != M.end()) res += ll(it->second) * M[nd];
}
printf("%I64d\n", res / 2);
return 0;
}
C. Cellular Network
思路
对于这种最大值最小化的题, 一眼二分。
二分出一个答案x后, 去判断。
可以枚举每个城市, 并找出左右两个最近的通信网塔, 然后算出它的距离, 并与x进行判断。
找一个城市左右相邻的蜂窝塔可以在套个二分(先把塔排个序即可)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n, m;
ll a[100010];
ll b[100010];
ll ans = -1;
bool check(int r)
{
//cout << r << endl;
for(int i = 1; i <= n; i++)
{
int p = lower_bound(b+1, b+m+1, a[i]) - b;
//cout << a[i] << " " << b[p-1] << " " << b[p] << endl;
if(min(b[p] - a[i], a[i] - b[p-1]) > r)
{
return false;
}
}
return true;
}
int main()
{
cin >> n >> m;
b[0] = -4e9-1;
b[m+1] = 4e9+1;
for(int i = 1; i <= n; i++)
{
cin >> a[i];
}
for(int i = 1; i <= m; i++)
{
cin >> b[i];
}
sort(b+1, b+m+1);
ll l = 0;
ll r = 2e9+1;
while(l <= r)
{
int mid = l + r >> 1;
//cout << mid << " " << check(mid) << endl;
if(check(mid))
{
ans = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
cout << ans << endl;
return 0;
}
大佬
既然你都能直接找到每个城市的最小距离了, 直接取max不行吗???
ll A[101010];
ll B[101010];
void solve() {
int i,j,k,l,r,x,y; string s;
cin>>N>>M;
FOR(i,N) cin>>A[i];
B[0]=-1LL<<40;
FOR(i,M) cin>>B[i+1];
B[M+1]=1LL<<40;
M+=2;
ll mi=0;
FOR(i,N) {
x = lower_bound(B,B+M,A[i])-B;
mi=max(mi,min(A[i]-B[x-1],B[x]-A[i]));
}
cout<<mi<<endl;
}
D. Road to Post Office
思路
大模拟;仔细思考一下,就会发现:要不就用一种交通工具, 要不就用两种。先想用一种的:假设走, 那么就为
b
×
d
b\times d
b×d
假设坐车, 那么就为
(
⌊
k
d
⌋
×
(
k
×
a
+
t
)
+
(
d
m
o
d
k
)
×
a
(\lfloor\frac{k}{d}\rfloor\times(k\times a+t) +(d\bmod k)\times a
(⌊dk⌋×(k×a+t)+(dmodk)×a
两种的, 你会发现, 只能是先开车在走, 那么什么时候下车呢?
只有两种可能, 开k千米不修直接下车, 开到还小于k千米时,下车不修直接走。
为什么不能在中间呢。
显然, 如果汽车时间少, 肯定尽量开, 否则, 开完就快走, 怎么样也不会在中间弃车。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll d, k, a ,b, t;
ll ans = 1e18;
int main()
{
cin >> d >> k >> a >> b >> t;
if(d < k)
{
cout << d * a << endl;
return 0;
}
ans = min(ans, (d / k) * (k * a + t) + (d % k) * a);
//cout << ans << endl;
ans = min(ans, d * b);
//cout << ans << endl;
ans = min(ans, k * a + (d - k) * b);
//cout << ans << endl;
ans = min(ans, (d / k) * (k * a + t) - t + (d % k) * b);
cout << ans << endl;
return 0;
}
dalao
直接枚举走的步数即可, 实际上, 肯定不会全走下来, 车的速度一定比走的快
ll D,A,K,B,T;
void solve() {
int i,j,k,l,r,x,y; string s;
cin>>D>>K>>A>>B>>T;
if(A*K+T>=B*K) {
cout<<min(D,K)*A + max(0LL,D-K)*B << endl;
}
else {
ll mi=1LL<<60;
for(x=0;x<=min(D,K);x++) {
ll mv=D-x;
ll fix=max(0LL,(mv+K-1)/K-1);
mi=min(mi,x*B + A*(D-x) + fix*T);
}
cout<<mi<<endl;
}
}
E. Analysis of Pathes in Functional Graph
思路
一眼倍增, fa, minn, w分别记录祖先编号, 当前点到祖先点的最小值与权值和。
O
(
n
l
o
g
k
)
O(nlog_k)
O(nlogk)
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
ll k;
int fa[100010][35];//log 1e10 = 33
int minn[100010][35];
ll w[100010][35];
ll ksm(ll a, int b)
{
ll res = 1;
while(b)
{
if(b & 1)
{
res = res * a;
}
a = a * a;
b >>= 1;
}
return res;
}
int main()
{
cin >> n >> k;
for(int i = 0; i < n; i++)
{
int x;
cin >> x;
fa[i][0] = x;
}
for(int i = 0; i < n; i++)
{
int z;
cin >> z;
w[i][0] = z;
minn[i][0] = z;
}
for(int i = 1; i <= 33; i++)
{
for(int j = 0; j < n; j++)
{
fa[j][i] = fa[fa[j][i-1]][i-1];
minn[j][i] = min(minn[j][i-1], minn[fa[j][i-1]][i-1]);
w[j][i] = w[j][i-1] + w[fa[j][i-1]][i-1];
}
}
// for(int i = 0; i < n; i++)
// {
// for(int j = 0; j <= 2; j++)
// {
// cout << minn[i][j] << " ";
// }
// cout << endl;
// }
// for(int i = 0; i < n; i++)
// {
// for(int j = 0; j <= 2; j++)
// {
// cout << w[i][j] << " ";
// }
// cout << endl;
// }
for(int i = 0; i < n; i++)
{
//cout << i << ":" << endl;
ll s = 0;
int m = 1e8;
ll depth = k;
int now = i;
for(int j = 33; j >= 0; j--)
{
//cout << j << " " << depth << endl;
if(ksm(2ll, j) <= depth)
{
depth -= ksm(2ll, j);
s = s + w[now][j];
m = min(m, minn[now][j]);
now = fa[now][j];
}
//cout << j << ": " << s << " " << m << endl;
}
cout << s << " " << m << endl;
}
return 0;
}
dalao
在内层跳k步时可以直接对k进行二进制分解, 类似于快速幂的思想。
int N;
ll K;
int F[101010][41];
ll W[101010][41];
ll S[101010][41];
void solve() {
int i,j,k,l,r,x,y; string s;
cin>>N>>K;
FOR(i,N) cin>>F[i][0];
FOR(i,N) cin>>W[i][0], S[i][0]=W[i][0];
FOR(i,40) {
FOR(x,N) F[x][i+1]=F[F[x][i]][i];
FOR(x,N) W[x][i+1]=min(W[x][i],W[F[x][i]][i]);
FOR(x,N) S[x][i+1]=S[x][i]+S[F[x][i]][i];
}
FOR(i,N) {
ll X=K;
ll mi=1LL<<40;
ll tot=0;
int cur=i;
FOR(j,40) if(X&(1LL<<j)) {
mi=min(mi,W[cur][j]);
tot+=S[cur][j];
cur=F[cur][j];
}
cout<<tot<<" "<<mi<<endl;
}
}