CF702

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 2xai表示。
又因为需要 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;
	}
	
	
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值