1. 程式人生 > >#數論、離散化、樹狀陣列# 2018中國大學生程式設計競賽 - 網路選拔賽

#數論、離散化、樹狀陣列# 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;
}