#数论、离散化、树状数组# 2018中国大学生程序设计竞赛 - 网络选拔赛

题目链接

 

1001. Buy and Resell

Problem Description

The Power Cube is used as a stash of Exotic Power. There are n cities numbered 1,2,…,n where allowed to trade it. The trading price of the Power Cube in the i-th city is ai dollars per cube. Noswal is a foxy businessman and wants to quietly make a fortune by buying and reselling Power Cubes. To avoid being discovered by the police, Noswal will go to the i-th city and choose exactly one of the following three options on the i-th day:

1. spend ai dollars to buy a Power Cube
2. resell a Power Cube and get ai dollars if he has at least one Power Cube
3. do nothing

Obviously, Noswal can own more than one Power Cubes at the same time. After going to the n cities, he will go back home and stay away from the cops. He wants to know the maximum profit he can earn. In the meanwhile, to lower the risks, he wants to minimize the times of trading (include buy and sell) to get the maximum profit. Noswal is a foxy and successful businessman so you can assume that he has infinity money at the beginning.

 Input

There are multiple test cases. The first line of input contains a positive integer T (T≤250), indicating the number of test cases. For each test case:
The first line has an integer n. (1≤n≤105)
The second line has n integers a1,a2,…,an where ai means the trading price (buy or sell) of the Power Cube in the i-th city. (1≤ai≤109)
It is guaranteed that the sum of all n is no more than 5×105.

 Output

For each case, print one line with two integers —— the maximum profit and the minimum times of trading to get the maximum profit.

 

Description:

给定n个商店,每个商店只能买或卖一次,并且商品的买入或卖出的价格固定,问最大能得到的利润是多少,保证最大利润的同时需要保证交换次数最小。

 

Solution:

优先队列。

将n个数拆成左右两列,左边表示买,右边表示卖,从左向右连边即表示买入和卖出。考虑第i天是否卖出,一定是在左边列的前 i-1 个中找一个还未配对的最小值和其配对进行买卖获益最大,如果最小值大于等于当的第天的价格就不交易。

配对时需要注意,如果当前配对的买入价格和之前某次配对的卖出价格相同,那么就可以将两条边合并为1条,交易次数减少而获利不变。用堆维护可买入的东西,set/hash维护已卖出的东西即可
 

 

Code:

 

 

1004. Find Integer

Problem Description

people in USSS love math very much, and there is a famous math problem .

give you two integers n,a,you are required to find 2 integers b,c such that an+bn=cn.

Input

one line contains one integer T;(1≤T≤1000000)

next T lines contains two integers n,a;(0≤n≤1000,000,000,3≤a≤40000)

Output

print two integers b,c if b,c exits;(1≤b,c≤1000,000,000);

else print two integers -1 -1 instead.

 

Description:

T组数据,给出 a 和 n,求满足 a^{^{n}}+b^{n}=c^{n} 的 b 和 c。

 

Range:

1 ≤ T ≤ 1000000

0 ≤ n ≤ 1000,000,000

3 ≤ a ≤ 40000

1 ≤ b, c ≤ 1000,000,000

 

Solution:

根据费马大定理:当整数 n > 2 时,关于x, y, z的方程 x^n + y^n = z^n 没有正整数解。

对于一下几种情况讨论:

n > 2 时,根据费马大定理不存在整数解。

n == 0 时,a^0 + b^0 = 1+1 = 2 ≠ c^0 = 1,输出 -1 -1;

n == 1 时,满足 a + b = c 即可;

n == 2 时,即勾股定理,相关公式为:

  • 当 a 为大于1的奇数(2n + 1)时,b = 2 * n * (n + 1),c = 2 * n * (n + 1) + 1;
  • 当 a 为大于4的偶数(2n)时,b = n^2 - 1,c = n^2 + 1。

 

关于勾股数的其他规律:

1. 如果直角三角形短直角边为奇数,另一条直角边与斜边是两个连续自然数,则两边之和是短直角边的平方。

即:a = 2 * n + 1,b = 2 * n * (n+1),c = 2 * n * (n+1) + 1。

例如:(3、4、5),(5、12、13),(7、24、25)、(9、40、41)

2. 如果要得到一组互质的勾股数,则可以用以下规律计算:a = 4n,b = 4n^2 - 1,c = 4n^2 + 1 (n为正整数) 

 

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MaxN = 1e5 + 5;

int main () 
{
    int t; scanf("%d", &t);
    while(t--) {
		LL n, a;
    	scanf("%lld %lld", &n, &a);
    	LL b = -1, c = -1;
    	if(n == 1) b = 1, c = a + 1;
		if(n == 2 && a >= 3) {
			if(a % 2 == 1) {
				LL base = (a - 1) / 2;
				b = 2 * base * (base+1);
				c = b + 1;
			}
			else {
				LL base = a / 2;
				b = base * base - 1;
				c = b + 2;
			}
		}
		printf("%lld %lld\n", b, c);
	}
    return 0;
}

 

1010. YJJ's Salesman

Problem Description

YJJ is a salesman who has traveled through western country. YJJ is always on journey. Either is he at the destination, or on the way to destination.
One day, he is going to travel from city A to southeastern city B. Let us assume that A is (0,0) on the rectangle map and B (109,109). YJJ is so busy so he never turn back or go twice the same way, he will only move to east, south or southeast, which means, if YJJ is at (x,y) now (0≤x≤109,0≤y≤109), he will only forward to (x+1,y), (x,y+1) or (x+1,y+1).
On the rectangle map from (0,0) to (109,109), there are several villages scattering on the map. Villagers will do business deals with salesmen from northwestern, but not northern or western. In mathematical language, this means when there is a village k on (xk,yk) (1≤xk≤109,1≤yk≤109), only the one who was from (xk−1,yk−1) to (xk,yk) will be able to earn vk dollars.(YJJ may get different number of dollars from different village.)
YJJ has no time to plan the path, can you help him to find maximum of dollars YJJ can get.

Input

The first line of the input contains an integer T (1≤T≤10),which is the number of test cases.

In each case, the first line of the input contains an integer N (1≤N≤105).The following N lines, the k-th line contains 3 integers, xk,yk,vk (0≤vk≤103), which indicate that there is a village on (xk,yk) and he can get vk dollars in that village.
The positions of each village is distinct.

 

Description:

有N个村庄 (x, y >= 1 && x, y <=1e9 ) ,每到一个村庄 可以选择向下、向右、向右下方走,每个村庄有一个贡献值,只有当从左上方来到村庄时才可以得到当前村庄的贡献值。

 

Solution:

离散化 + 排序+树状数组维护区间最大值。

n 在1e5内,  图在1e9内 ,  所以需要离散化坐标,   对 x 排序,  对 y 离散化。(虽然实际测试数据范围压根没有1e9)

如果用传统 dp ,状态转移很容易得出   但很明显会超时。

首先,不难得出, 每行每列只能取一个。

由于只有左下方的可以转移过来,所以按照 x 从小到大,  y 从右到左进行排序。

通过前一行的最优值去转移得到当前行的最优值,对y轴利用树状数组维护前面得最大值,这样每次得到的最大值加上当前点的贡献就是走到当前这个点取到的最大价值。 

 

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
#include <cstdlib>
#include <string>
#include <iostream>
#include <vector>
#include <map>
#include <queue>
#define mst(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int MaxN = 1e5 + 5;

struct node{
	int x, y, w;
}a[MaxN];

int n;
int y[MaxN], premax[MaxN];

bool cmp(node p, node q) { 
	return p.x < q.x || (p.x == q.x && p.y > q.y);
}

int lowbit(int x) { return x & (-x); }

void update(int p, int x) {
	for(int i = p; i <= MaxN; i += lowbit(i)) premax[i] = max(premax[i], x);
}

int getmax(int p) {
	int res = 0;
	for(int i = p; i > 0; i -= lowbit(i)) res = max(premax[i], res);
	return res;
}

int main () 
{
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);

    int t; cin >> t;
    while(t--) {
		mst(premax, 0);
		cin >> n;
		for(int i = 1; i <= n; i++) {
			cin >> a[i].x >> a[i].y >> a[i].w;
			y[i] = a[i].y;
		}
		sort(y + 1, y + 1 + n);
		int len = unique(y + 1, y + 1 + n) - (y + 1);
		for(int i = 1; i <= n; i++) 
			a[i].y = lower_bound(y+1, y+1+len, a[i].y) - y; //相当于将a[i].y加一, 因为树状数组下表不能为0
		sort(a + 1, a + 1 + n, cmp);
		for(int i = 1; i <= n; i++) {
			int res = getmax(a[i].y - 1) + a[i].w; //查询时需要减去多加的一
			update(a[i].y, res);
		}
		cout << getmax(MaxN) << endl;

	}
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值