算阶1的例题集合(未完成)

The Pilots Brothers refrigerator 枚举,位运算

题目大意:
  给出4×4共16个门把手,改变一个门把手(打开或关闭)需要同时改变同行同列的门把手,当所有门把手都打开时才能打开门。+代表关,-代表开。输出开门的最小次数和其中一种方案
  
input

-+--
----
----
-+--

output

6
1 1
1 3
1 4
4 1
4 3
4 4

题解
寻找只改变一个点的方法:改变这个点所在行和所在列的所有点各一次
用num数组记录下每个点需要更改的次数
显而易见,如果一个点被改变偶数次相当于没有改变
最后对num数组进行判断即可

代码

#include<bits/stdc++.h>
using namespace std;
int num[5][5]={}, ans = 0;
int main(){
	char ch;
	for(int i = 1; i <= 4; i++)
		for(int j = 1; j <= 4; j++){
			cin>>ch;
			if(ch == '+'){
				for(int k = 1; k <= 4; k++){
					num[i][k]++;
					num[k][j]++;
				}
				num[i][j]--;	
			}	
		}
	for(int i = 1; i <= 4; i++)
		for(int j = 1; j <= 4; j++)
			if(num[i][j] & 1) ans++;
	printf("%d\n", ans);
	for(int i = 1; i <= 4; i++)
		for(int j = 1; j <= 4; j++)
			if(num[i][j] & 1) 
				printf("%d %d\n", i, j);
	return 0;
}

在这里插入图片描述

Fractal Streets(还有一定不解,回头补(标记)) 递归,分形

题目描述
城市设想了这样的一个规划方案,如下图所示:
在这里插入图片描述求如果城市发展到 了等级N,编号为A 和B 的两个街区的直线距离是多少。街区的距离指的是街区的中心点之间的距离,每个街区都是边长为10 米的正方形。

输入格式
第一行有一个整数T 表示测试数据的数目。
每组测试数据包含一行三个整数N, A, B,表示城市等级以及两个街区的编号。

输出格式
对于每组测试数据,在单独的一行内输出答案,四舍五入到整数。

样例输入

3
1 1 2
2 16 1
3 4 33

样例输出

10
30
50

题解
题目求距离,只要求出两点的坐标,即可轻松求得距离。
类型是分形,我们会发现等级高的城市是可以分成四份的,每一部分都可以经过旋转得到小一级的城市,我们将坐标存在一个pair里,不停地递归下去,分类讨论,将坐标推回来。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll  n;

pair <ll, ll> calc(ll l, ll m){
	if(l == 0) return make_pair(0, 0);//如果城市等级为0
	ll len = 1ll << (l - 1)//求矩形的边长
	ll cnt = 1ll << (2 * l - 2);//求矩阵中的城市数
	pair<ll, ll> p = calc(l - 1, m % cnt);//用于判断属于左上左下右上右下,还提取坐标
	ll x = p.first, y = p.second;//拿出之前递推回来的坐标
	ll z = m / cnt;//用于判断属于左上左下右上右下,哪一个部分,分类递归
	if(z == 0)	return make_pair(y, x);
	if(z == 1)	return make_pair(x, y + len);
	if(z == 2)	return make_pair(x + len, y + len);
	if(z == 3)	return make_pair(2 * len - y - 1,  len - x - 1);
	//这个就是多写一些坐标,寻找规律
}

double gg(ll x1,long x2,ll y1,ll y2){
	double x = sqrt( 1.00000*double(x1 - x2) * double(x1 - x2) 
               	   + 1.00000*double(y1 - y2) * double(y1 - y2) );
	return x;
}//求平方

int main(){
	scanf("%lld", &n);
	for(int i = 1; i <= n;i++){
		ll l, x, y;
		scanf("%lld%lld%lld", &l, &x, &y);
		pair<ll, ll> a, b;
		a = calc(l, x - 1);
		b = calc(l, y - 1);//减1是为了方便后面位置(四大块)的判断
		printf("%.0lf\n", round(10 *gg(a.first, b. first, a.second, b.second)));
	}
	return 0;
} 

在这里插入图片描述

激光炸弹
前缀和

Description
一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标。现在地图上有n个目标,用整数Xi,Yi表示目标在地图上的位置,每个目标都有一个价值。激光炸弹的爆破范围必须和x,y轴平行。若目标位于爆破正方形的边上,该目标将不会被摧毁。

Input
输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示xi,yi,vi

Output
输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

Sample Input

2 1
0 0 1
1 1 1

Sample Output

1

题解
推导两个公式即可

二维前缀和:

mapp[x][y] = mapp[x][y] + mapp[x-1][y] + mapp[x][y-1] - mapp[x-1][y-1];

在这里插入图片描述
用前缀和求R*R的矩阵和:

ans = mapp[x][y] - mapp[x-r][y] - mapp[x][y-r] + mapp[x-r][y-r];

在这里插入图片描述
代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int n, r, maxx =-1, A =0;
int mapp[5005][5005]={0};

int main(){
	int maax =r, maay =r; 
	for(int i = 1; i <= n; i++){
		int x, y, v;
		scanf("%d%d%d", &x, &y, &v);
		mapp[x+1][y+1] += v;
		maax = max(maax, x+1);
		maay = max(maay, y+1);
	}
	for(int x = 1; x <= maax; x++)
		for(int y = 1; y <= maay; y++)
			mapp[x][y] += mapp[x-1][y] + mapp[x][y-1] - mapp[x-1][y-1];
	for(int x = r; x <= maax; x++)
		for(int y = r; y <= maay; y++){
			A = mapp[x][y] - mapp[x-r][y] - mapp[x][y-r] + mapp[x-r][y-r];
			maxx = max(maxx, A);
		}
	printf("%d\n", maxx);
	return 0;
}

在这里插入图片描述

数列操作(差分)问题
差分

题目描述
给定一个长度为n的数列{a1,a2…an},每次可以选择一个区间[l,r],使这个区间内的数都加一或者都减一。
问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

输入格式
第一行一个正整数n
接下来n行,每行一个整数,第i+1行的整数表示ai。

输出格式
第一行输出最少操作次数
第二行输出最终能得到多少种结果

input

4
1
1
2
2

output

1
2

题解
A A A数列的差分序列 B B B
[ l , r ] [l,r] [l,r]内的数都 + 1 +1 +1或都 − 1 -1 1 = = == == B [ l ] + 1 , B [ r + 1 ] − 1 B[l] + 1,B[r+1] - 1 B[l]+1B[r+1]1”(或反之)。
A A A数列中的所有数全部相等的条件 = = == == 使 B B B序列 = 0 ( 2 ≤ i ≤ n ),最后数列中的数即 B [ 1 ] B[1] B[1]
要将 B B B数列中第 2 2 2项至第 n n n项全部变为0并使操作次数最少
首先我们将每个负数和每个正数配对执行操作
B B B数列中第 2 2 2至第 n n n项所有正数分别求和得到的值为p,负数分别求和得到的值的绝对值为q
这一步的操作次数即为 m i n ( p , q ) min( p,q) min(p,q)
此时还剩余abs(p-q)的数没有变为0
每次操作我们可以将其与 B [ 1 ] B[1] B[1] B [ n + 1 ] B[n+1] B[n+1]配对进行操作,操作次数为 a b s ( p − q ) abs(p-q) abs(pq).
容易看出,最终 B [ 1 ] B[1] B[1]的可能取值有 a b s ( p − q ) + 1 abs(p-q)+1 abs(pq)+1种。
因此,第一问的答案即为 m a x ( p , q ) max(p,q) max(p,q),第二问的答案即为 a b s ( p − q ) + 1 abs(p-q)+1 abs(pq)+1

代码

#include<bits/stdc++.h>
#define ll long long
#define memset(x) memset(x, 0, sizeof(x))
using namespace std;
int n, A[100010], B[100010];
ll ans1=0, ans2=0, sum1=0, sum2=0;

int main(){
	scanf("%d", &n);
	memset(A);memset(B);
	for(int i = 1; i <= n; i++){
		scanf("%d", &A[i]);
		B[i] = A[i] - A[i-1];
		if(B[i] > 0 && i!=1) ans1+=B[i];
		if(B[i] < 0 && i!=1) ans2-=B[i];
	}
	sum1 = max(ans1,ans2);
	sum2 = abs(ans1-ans2) +1;
	printf("%lld\n%lld", sum1, sum2);
	return 0;
}

在这里插入图片描述

货仓选址 中位数

题目描述
在一条数轴上有N家商店,它们的坐标分别为 A[1]~A[N]。求把货仓建在数轴上何处,可以使得货仓到每家商店的距离之和最小,求距离。

Input
第一行一个整数N,第二行N个整数A[1]~A[N]。

Output
一个整数,表示距离之和的最小值

Sample Input

4
6 2 9 1

Sample Output

12

题解
奇数选最中间的那个点,偶数选最中间那两点间任意一点
证明
若随意取一点,左边有 P P P个点,右边有 Q Q Q个点,若 P P P大于 Q Q Q,向左一格,距离可减少 ( P − Q ) (P-Q) PQ,所以当 P = = Q P==Q P==Q时,距离最小。

代码

#include<bits/stdc++.h>
using namespace std;
int num, N, ans=0, A[100010];

int main(){
	scanf("%d", &N);
	for(int i = 1; i <= N; i++)
		scanf("%d", &A[i]);
	sort(A+1, A+1+N);
	if(N & 1) num = A[(N+1)/2];
	else num = A[N/2];
	for(int i = 1; i <= N; i++)
		ans += abs(A[i] - num);
	printf("%d", ans);
	return 0;
} 

在这里插入图片描述

七夕祭 中位数

题目大意
矩形的祭典会场由N 排M 列共计N×M 个摊 点组成。判断能否通过恰当地布 置会场,使得各行中cl 感兴趣的摊点数一样多,或者各列中cl 感兴趣的摊点数也一样多。只能交换两个相邻的摊点,每一行或每一列的第一个位置和最后一个位置也算作相邻。问两个要求能否满足,至少需要交换多少次摊点。

输入格式
第一行包含三个整数N 和M 和T。T 表示cl 对多少个摊点感兴趣。
接下来T 行,每行两个整数x, y,表示cl 对处在第x 行第y 列的摊点感兴趣。

输出格式
首先输出一个字符串。
如果能满足Vani 的全部两个要求,输出both;
如果通过调整 只能使得各行中cl 感兴趣的摊点数一样多,输出row;
如果只能使各列中cl 感兴趣的摊点 数一样多,输出column;
如果均不能满足,输出impossible。
如果输出的字符串不是impossible, 接下来输出最小交换次数,与字符串之间用一 个空格隔开。

样例输入1

2 3 4
1 3
2 1
2 2
2 3

样例输出1

row 1

样例输入2

3 3 3
1 3
2 2
2 3

样例输出2

both 2

题解
经过分析发现,横与列互相不影响,即交换左右相邻的摊点只会改变每列的感兴趣摊位值,而不会改变每行的感兴趣摊位值,所以我们把问题分为两个问题
1.通过最小次数的左右交换使每列cl感兴趣的摊点数相同
2.通过最小次数的上下交换使每行cl感兴趣的摊点数相同
下面以1为例
首先,若T%m不为0,则必然不能完成

类比均分纸牌

均分纸牌问题
共有T张牌,M个人排一排,每人C[1]~C[M]张纸牌,需要通过左右交换使纸牌数相同
举个例子
4个人
各有1,7,5,3张
最后每个人需要4张
所以,从头到尾遍历,优先保证前面的数到达最后需要达到的值
1<——232号变为42号不变
3号——>414号变为4

如果使用每个人的牌数来判断,每次还要更新两者的牌数,交换次数是| C [ i ] C[i] C[i] - T M \frac{T}{M} MT|
引进前缀和 S 【 】 S【】 S,和差值数列 A 【 】 A【】 A, A 【 】 A【】 A表示| C [ i ] C[i] C[i] - T M \frac{T}{M} MT|, S 【 】 S【】 S表示 A 【 】 A【】 A的前缀和,这样我们保证 S 【 】 S【】 S为0即可,交换次数为 ∣ S [ i ] ∣ |S[i]| S[i]

七夕祭这题与均分纸牌有一个区别,它是环形的,我们就需要一个 f o r for for循环枚举第一个摊位,然后进行比较,但是这样的复杂度是不可以被接受的。
思考:这个时候的交换次数为 ∑ i = 1 M \sum_{i=1}^{M} i=1M ∣ S [ i ] − S [ k ] ∣ \left |S[i]-S[k] \right | S[i]S[k],如果保证这个累加和最小,不就是货仓问题吗?所以从小到大将S【】排序,k就是最中间的那个数对应的列数。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

struct psx{int num, sum;} s[100010];
bool mycmp(psx a, psx b){return a.sum < b.sum;}
int T, n, m;
ll ans = 0;
int cj[3][100010];

bool work(int a, int b){
	if( T%a ) return 0;//如果不能均分
	memset(s, 0, sizeof(s));
	for(int i = 1; i <= a; i++){
		cj[b][i] -= T/a;//转换为上面所说的A数组
		s[i].sum = cj[b][i] + s[i-1].sum;//计算上面所说的S数组
		s[i].num = i;
	}
	sort(s+1, s+1+a, mycmp);//排序
	for(int i = 1; i <= a; i++)
		ans += abs(s[a/2+1].sum - s[i].sum);
	//因为交换次数是要累加每一行的,所以顺序打乱不影响最终结果
	return 1;
}

int main(){
	scanf("%d%d%d", &n, &m, &T);
	for(int i = 1; i <= T; i++){
		int x, y;
		scanf("%d%d", &x, &y);
		cj[1][x]++;//计算每行有几个感兴趣摊位
		cj[2][y]++;//计算每列有几个感兴趣摊位
	}
	bool flag1 = work(n, 1), flag2 = work(m, 2);
	if(flag1 && flag2) printf("both %lld", ans);
	else if(flag1 && !flag2) printf("row %lld", ans);
	else if(!flag1 && flag2) printf("column %lld", ans);
	else if(!flag1 && !flag2) printf("impossible");
	return 0;
}

在这里插入图片描述

Running Median

中位数,对顶堆

描述
你需要写一个程序,读入一个整数序列,每读入奇数个数后输出当前的中位数。

输入
输入的第一行包含一个整数 P P P,这是询问的组数。
每组输入的第一行为该组输入的序号和该序列的大小M,保证序列有奇数个数。
接下来有若干行,每行最多十个整数,描述这个序列。

输出
对于每组输入,输出的第一行应是该组输入的序号和该组输出的大小。
接下来若干行,每行最多十个整数,描述你的输出。

样例输入

3 
1 9 
1 2 3 4 5 6 7 8 9 
2 9 
9 8 7 6 5 4 3 2 1 
3 23 
23 41 13 22 -3 24 -31 -11 -8 -7 
3 5 103 211 -311 -45 -67 -73 -81 -99 
-33 24 56

样例输出

1 5
1 2 3 4 5
2 5
9 8 7 6 5
3 12
23 23 22 22 13 3 5 5 3 -3 
-7 -3

题解
使用对顶堆的做法
建立两个堆,一个小根堆,一个大根堆。
我们运用代码,使输入的 i i i个数,从小到大的前 ( i / 2 + 1 ) (i/2+1) i/2+1个数在大根堆,后 i / 2 i/2 i/2个数在小根堆,因为每输入奇数个数就要输出,且 M M M也是奇数,所以 i i i一定是奇数.那么显然,大根堆堆顶就是中位数。

那么,怎么存数呢?
首先明确两个要求
1.大根堆有 ( i / 2 + 1 ) (i/2+1) i/2+1个数,小根堆有 i / 2 i/2 i/2个数
2.大根堆的任意数必然小于小根堆的任意数

好!得出做法了!
每次放进两个数,比上一个中位数大的放进小根堆,否则放进大根堆。
放完以后,如果根堆中数量不符合,则取出堆顶给另一个根堆,直至符合。

注意:题目要求输出,每行最多十个整数,所以一组数据超过十个要换行。
代码

#include<bits/stdc++.h>
#define sc(x) scanf("%d", &x);
using namespace std;

priority_queue< int,vector< int >,greater< int > > q;//小根堆
priority_queue< int,vector< int >,less< int > > p;//大根堆
int P, x, M, a, b, ans = 0;
int main(){
	sc(P);
	int num = 0;
	while(P--){
		sc(x); sc(M);
		printf("%d %d\n",x, M/2+1);//输出序号和中位数个数
		sc(a);  num = a;
		printf("%d", a);//第一个数必然是第一个中位数,输出
		ans++;//记录输出了几个中位数
		q.push(a);//放进小根堆
		for(int i = 2; i <= M; i +=2){
			sc(a); sc(b);
			if(a >= num) q.push(a);
			else p.push(a);
			if(b >= num) q.push(b);
			else p.push(b);
			//放进它们该进的根堆
			while(p.size() > (i+1)/2){
				x = p.top();
				q.push(x);
				p.pop();
			}
			while(p.size() < (i+1)/2){
				x = q.top();
				p.push(x);
				q.pop();
			}
			//调整根堆中元素的个数直至符合
			num = q.top();
			ans++;//输出中位数,记录中位数个数
			printf(" %d",num);
			if(ans == 10) printf("\n"), ans = 0;//超过十个就换行
		}
		if(ans != 10) printf("\n");
		while(q.size()) q.pop();
		while(p.size()) p.pop();//清空根堆
		ans = 0;
	}
	return 0;
} 

在这里插入图片描述

占卜DIY 模拟

题目大意
一副去掉大小王的扑克共52张,均分为13堆,编号1~13,第13堆称作“生命牌”。4张K被称作死神。
初始状态下,所有的牌背面朝上扣下。
流程如下:
1.抽取生命牌中的最上面一张(第一张)。
2.把这张牌翻开,正面朝上,放到牌上的数字所对应编号的堆的最上边。(例如抽到2,正面朝上放到第2堆牌最上面,又比如抽到J,放到第11堆牌最上边,注意是正面朝上放)
3.从刚放了牌的那一堆最底下(最后一张)抽取一张牌,重复第2步。(例如你上次抽了2,放到了第二堆顶部,现在抽第二堆最后一张发现是8,又放到第8堆顶部…)
4.在抽牌过程中如果抽到K,则称死了一条命,就扔掉K再从第1步开始。
5.当发现四条命都死了以后,统计现在每堆牌上边正面朝上的牌的数目,只要同一数字的牌出现4张正面朝上的牌(比如4个A),则称“开了一对”,当然4个K是不算的。
6.统计一共开了多少对。

Input Format
一共13行,为每堆牌的具体牌是什么(不区分花色只区分数字),每堆输入的顺序为从上到下。
为了便于读入,用0代表10,那么A,J,Q,K(大写)就不用说了吧。。。

Output Format
一共开了几对。

Sample Input

    8 5 A A
    K 5 3 2
    9 6 0 6
    3 4 3 4
    3 4 4 5
    5 6 7 6
    8 7 7 7
    9 9 8 8
    9 0 0 0
    K J J J
    Q A Q K
    J Q 2 2
    A K Q 2

Sample Output

9

Hint

注解:第一条命死后前12堆牌变成了这个样子:

A A A 8

K 5 3 2

3 9 6 0

4 4 3 4

5 5 3 4

6 6 5 6

7 7 7 7

8 8 8 9

9 9 0 0

0 K J J

J Q A Q//抽到这里的K死掉了

J Q 2 2

第二条命由于K在生命牌中,所以直接死掉,不变。

第三条命死后前12堆牌变成了这个样子:

A A A A

2 2 2 K

3 3 3 3

4 4 4 4

5 5 5 5

6 6 6 6

7 7 7 7

8 8 8 8

9 9 9 9

0 0 0 0//抽到这里的K死掉了

J J J Q

Q Q J Q

第四条命死后前12堆牌变成了这个样子:

A A A A

2 2 2 2//抽到这里的K死掉了

3 3 3 3

4 4 4 4

5 5 5 5

6 6 6 6

7 7 7 7

8 8 8 8

9 9 9 9

0 0 0 0

J J J Q

Q Q J Q

最后发现在所有已经正面朝上的牌中,A 2 3 4 5 6 7 8 109对牌“开”了,
(注意,第9堆牌中的最后一张虽然也是9,但是并没有被翻开!所以不能算)
因此输出9

题解
就是一道模拟,没什么可说的,注意一下牌堆的顺序以及最后的“对”的判断。

代码

#include<bits/stdc++.h>
using namespace std;
int num[15][100], sum[15], sun[15],ans=0;

void work(int a){
	num[a][++sun[a]] = a;
	sum[a]++;
	if(num[a][sum[a]] == 13) return;
	work(num[a][sum[a]]);
}

int main(){
	char ch;
	for(int i = 1; i <= 13; i++){
		sun[i] = 4;
		sum[i] = 0;
		for(int j = 4; j >= 1; j--){
			cin>>ch;
			if(ch == '0') num[i][j] = 10;
			else if(ch == 'J') num[i][j] = 11;
			else if(ch == 'Q') num[i][j] = 12;
			else if(ch == 'K') num[i][j] = 13;
			else if(ch == 'A') num[i][j] = 1;
			else num[i][j] = int(ch)-'0';
		}
	}
	for(int i = 4; i >= 1; i--)
		work(num[13][++sum[13]]);
	for(int i = 1; i <= 12; i++)
		if(sun[i] == 8) ans++;
	printf("%d", ans);
	return 0;
}

在这里插入图片描述

Sunscreen 贪心

题目大意
C头奶牛有minSPF_i和maxSPF_i,奶牛们准备了一大篮子防晒霜,一共L瓶,有不同的SPF值,可以供不同数量cover_i头奶牛使用。如果奶牛们涂的防晒霜,必须在自己的minSPF_i和maxSPF_i内,最多有几头奶牛可以涂防晒霜。

输入格式
第1行: 2个用空格隔开的整数:C和L
第2…C+1行: 第i+1行给出了适合第i头奶牛的SPF值的范围:minSPF_i以及 maxSPF_i
第C+2…C+L+1行: 第i+C+1行为了第i瓶防晒霜的参数:SPF_i和cover_i

输出格式
输出1个整数,表示最多有多少头奶牛能享受到日光浴

input

3 2
3 10
2 5
1 5
6 2
4 1

output

2

题解
一瓶防晒霜可以使用n次,相当于有n瓶这样的防晒霜,我们用v【】记录防晒霜的数量
将牛的minSPF从小到大排
for循环外层循环牛,内层寻找该头牛能用的SPF值最大的防晒霜
下面说一下,这样贪心的可行性:
每瓶防晒霜是否可用,会被minSPF和maxSPF两个条件限制,
因为牛已经排序,所以每个不低于当前奶牛的防晒霜都不会低于后面牛的minSPF,一定满足后面奶牛的minSPF要求,那么选SPF更大的防晒霜显然能尽可能地满足后面奶牛对maxSPF的要求。

代码

#include<bits/stdc++.h>
using namespace std;

struct psx{int mi,ma;} cow[2505];
int c, l, v[2505]={}, ans=0;
bool mycmp(psx a, psx b) {return a.mi > b.mi;}

int main(){
	scanf("%d%d", &c, &l);
	for(int i = 1; i <= c; i++)
		scanf("%d%d", &cow[i].mi, &cow[i].ma);
	for(int i = 1; i <= l; i++){
		int a, b;
		scanf("%d%d", &a, &b);
		v[a] += b;
	}
	sort(cow+1, cow+1+c, mycmp);
	for(int i = 1; i <= c; i++)
		for(int j = cow[i].ma; j >= cow[i].mi; j--)
			if(v[j])  {v[j]--; ans++; break;}
	printf("%d",ans);
	return 0;
}

在这里插入图片描述

To the Max 贪心

题目大意
一个N*N的矩阵,有正负数,求最大的子矩阵和

Sample Input

 4
 0 -2 -7  0 
 9  2 -6  2
-4  1 -4  1
-1  8  0 -2

Sample Output

15

题解
这类的题目都是一个套路,处理出每列的前缀和。
for循环列举两个行数,作为矩阵的上下边
从左往右扫,如果左边已扫的矩形和是正的就保留,继续增加下一列,如果是负的,那么一定不会和后面的几列构成最大值,就清空继续扫。

代码

#include<bits/stdc++.h>
using namespace std;
int n, maxx = -0x3f;
int num[105][105],sum[105][105];

int main(){
	scanf("%d", &n);
	memset(sum, 0, sizeof(sum));
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++){
			scanf("%d", &num[i][j]);
			sum[i][j] = sum[i - 1][j] + num[i][j];
		}//输入矩阵,sum存每列的前缀和
	for (int i = 1; i <= n; i++)
		for (int j = i; j <= n; j++){
			int ans = 0;
			for (int k = 1; k <= n; k++){
				if (ans > 0) ans += sum[j][k] - sum[i - 1][k];
				//如果左边的矩阵是正的,就保留它,增加宽为1,长是从i到j的矩形
				else ans = sum[j][k] - sum[i - 1][k];
				//如果之前矩形为负,清空它,重新开始计算
				maxx = max(ans, maxx);
			}
		}
	printf("%d", maxx);
	return 0;
}

在这里插入图片描述

Task 贪心

题意
有n个机器,m个任务。每个机器至多能完成一个任务。对于每个机器,有一个最大运行时间xi和等级yi,对于每个任务,也有一个运行时间xj和等级yj。只有当xi>=xj且yi>=yj的时候,机器i才能完成任务j,并获得500xj+2yj金钱。问最多能完成几个任务,当出现多种情况时,输出获得金钱最多的情况。

Sample Input

1 2
100 3
100 2
100 1

Sample Output

1 50004

题解
用x为第一判断,y为第二判断,将机器与任务排序,由大到小。
保证前面的任务(或机器)的x一定不小于后面的任务(或机器)的x。
x x x相同的情况下,保证前面的任务(或机器)的y一定不小于后面的任务(或机器)的y。
将任务作为最外层循环。
我们用机器的y作为下标存储一个 n u m num num数组, n u m 【 i 】 num【i】 numi表示,有 n u m 【 i 】 num【i】 numi个等级为i的机器还没有被用掉,空闲在那里。
j j j f o r for for循环,将x大于等于任务的机器加入 n u m num num数组。
被加进num数组的机器的x必然大于等于此时的任务以及后面的所有任务,所以便只需要判断y的大小就行了。
k k k循环,循环的是 n u m num num的下标,如果存在 n u m 【 i 】 ( i > = num【i】(i>= numii>=任务的 y ) y) y数组有值,则这个任务可以被完成。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int ni, mi, num[100010]={};
ll ans = 0, sum = 0;

struct psx{int x, y;} t[100010],m[100010];
bool mycmp(psx a, psx b){
	if(a.x == b.x) return a.y > b.y;
	return a.x > b.x;
}

int main(){
	scanf("%d%d", &ni, &mi);
	for(int i = 1; i <= ni; i++)
		scanf("%d%d", &m[i].x, &m[i].y);//机器
	for(int i = 1; i <= mi; i++)
		scanf("%d%d", &t[i].x, &t[i].y);//任务
	sort(m+1, m+ni+1, mycmp);
	sort(t+1, t+mi+1, mycmp);
	int j = 1;
	for(int i = 1; i <= mi; i++){//任务
		for(;j <= ni && m[j].x >= t[i].x; j++)//注意:j不会因为任务更改,重新赋初值
			num[m[j].y]++;//如果第j个机器可以完成第i个任务
		for(int k = t[i].y; k <= 100; k++)//y小于等于100,英文题面里有说
			if(num[k]){
				num[k]--;  sum++;
				ans += 500*t[i].x + 2*t[i].y;
				break;
			}	
	}
	printf("%d %lld",sum, ans);
	return 0;
}

Color a tree 贪心

题目大意:
Bob is very interested in the data structure of a tree. A tree is a directed graph in which a special node is singled out, called the “root” of the tree, and there is a unique path from the root to each of the other nodes.

Bob intends to color all the nodes of a tree with a pen. A tree has N nodes, these nodes are numbered 1, 2, …, N. Suppose coloring a node takes 1 unit of time, and after finishing coloring one node, he is allowed to color another. Additionally, he is allowed to color a node only when its father node has been colored. Obviously, Bob is only allowed to color the root in the first try.

Each node has a “coloring cost factor”, Ci. The coloring cost of each node depends both on Ci and the time at which Bob finishes the coloring of this node. At the beginning, the time is set to 0. If the finishing time of coloring node i is Fi, then the coloring cost of node i is Ci * Fi.

For example, a tree with five nodes is shown in Figure-1. The coloring cost factors of each node are 1, 2, 1, 2 and 4. Bob can color the tree in the order 1, 3, 5, 2, 4, with the minimum total coloring cost of 33.
在这里插入图片描述
Given a tree and the coloring cost factor of each node, please help Bob to find the minimum possible total coloring cost for coloring all the nodes.

Translation
有一棵树,每个节点都有一个代价基值Ci。现在要给每个点染色,第一个染根节点,其余的节点染色的时候其父节点必须已染色。每个节点染色会用掉一个时间单位,每个节点染色的代价是染完此节点时的总时间T*Ci。问染完全部节点所需要的最小代价。

Input
The input consists of several test cases. The first line of each case contains two integers N and R (1 <= N <= 1000, 1 <= R <= N), where N is the number of nodes in the tree and R is the node number of the root node. The second line contains N integers, the i-th of which is Ci (1 <= Ci <= 500), the coloring cost factor of node i. Each of the next N-1 lines contains two space-separated node numbers V1 and V2, which are the endpoints of an edge in the tree, denoting that V1 is the father node of V2. No edge will be listed twice, and all edges will be listed.

Output
For each test case, output a line containing the minimum total coloring cost required for Bob to color all the nodes.

input

5 1
1 2 1 2 4
1 2
1 3
2 4
3 5

output

33

题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int N, R, maid;
struct psx{int num, ans, sum, fa, vis;} p[1005];
int find(int x) {
	if (x != p[x].fa && p[p[x].fa].vis) 
		p[x].fa = find(p[x].fa);
	return p[x].fa;
}

int main() {
	scanf("%d%d", &N, &R);
	for(int i = 1; i <= N; i++) {
		scanf("%d", &p[i].sum);
		p[i].ans = p[i].sum;
		p[i].num = 1;
	}
	int v1, v2;
	for(int i = 1; i < N; i++) {
		scanf("%d%d", &v1, &v2);
		p[v2].fa = v1;
	}
	p[R].fa = R;
	for(int i = 1; i < N; i++) {
		double maxx = 0;
		for(int j = 1; j <= N; j++) {
			if(!p[j].vis && p[j].sum*1.0/p[j].num > maxx && j != R) {
				maid = j;
				maxx = p[j].sum*1.0/p[j].num;
			}
		}
		p[maid].vis = 1;
		int fa = find(maid);
		p[fa].ans += p[maid].ans + p[maid].sum * p[fa].num;
		p[fa].sum += p[maid].sum;
		p[fa].num += p[maid].num;
	}
	printf("%d", p[R].ans);
	return 0;
}

在这里插入图片描述

Genius ACM

倍增

题目大意:
ACM公司的质检部门会对生产出的CPU进行成组测试,对一组(若干个)CPU进行测试的方法如下:

  1. 随机从该组CPU中选取m 对(即2m 台),若总数不足2m 台,则选取尽量多对。
  2. 对于每一对CPU,测量它们之间的Relative Performance Difference (RPD),并把第i 对的RPD记为Di。RPD的计算方法在后面给出。
  3. 该组CPU由以下公式给出:
    在这里插入图片描述
  4. 该组CPU通过质检,当且仅当SPD≤k, 其中 k 是给定常数。
    现在,小S已经知道了n台各自的性能表现P1…Pn,两台CPU的RPD被定义为它们性能表现的差的绝对值。请你帮忙计算一下,至少把这些CPU分成多少段,才能使得每一段都能通过成组测试。

输入格式
每个测试点包含多组数 据,第一行整T 给出数据组。
对于每组数 据,第一行三个整n m k,第二行 n 个整数P1…Pn。

输出格式
对于每组数据,输出一个整表示答案。

input

2
5 1 49
8 2 1 7 9
5 1 64
8 2 1 7 9

output

2
1

数据范围

T≤12
1≤n,m≤5*10^5
0≤k≤10^18
0≤Pi≤220

题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int M = 6e5+10;
ll a[M], b[M], c[M], n, m, k, T, L, R, P, ans;

bool check(ll L, ll R, ll lr) {
	int t = L, len = R - L + 1;
	for (ll i = lr; i <= R; i++)
		b[i] = a[i];
	sort(b + lr, b + R + 1);
	if (L == lr)
		for (int i = L; i <= R; i++)
			c[i] = b[i];
	else {
		int i = L, j = lr;
		while (i < lr && j <= R)
			if (b[i] <= b[j]) c[t++] = b[i++];
			else c[t++] = b[j++];
		while (i < lr) c[t++] = b[i++];
		while (j <= R) c[t++] = b[j++];
	}
	ll tot = 0;
	for (ll i = L; i <= min(L+m-1, L + len/2 -1); i++)
		tot += (c[R-i+L] - c[i]) * (c[R-i+L] - c[i]);
	if (tot <= k) {
		for (int i = L; i <= R; i++) b[i] = c[i];
		return 1;
	}
	return 0;
}

int main() {
	scanf("%lld", &T);
	while( T-- ) { 
		scanf("%lld%lld%lld", &n, &m, &k);
		for(int i = 1; i <= n; i++)
			scanf("%lld", &a[i]);
		memset(b, 0, sizeof(b));
		memset(c, 0, sizeof(c));
		ll sum = 0; 
		L = R = P = 1;
		b[1] = a[1];
		while(R < n) {
			if(!P) { sum++; P = 1; R++; L = R; b[L] = a[L]; continue; }
			if(P) 
				if(R+P <= n && check(L, R+P, R+1)) 
					{ R += P; P *= 2; if(R == n) break;}
				else P /= 2;
		}
		if(R == n) sum++;
		printf("%lld\n", sum);
	}
	return 0;
}

在这里插入图片描述

Stall Reservation

贪心

题目大意:
FJ的 N ( 1 < = N < = 50 , 000 ) N(1<=N<=50,000) N(1<=N<=50,000)头奶牛有固定的产奶时间,为时间段 [ A , B ] ( 1 < = A < = B < = 1 , 000 , 000 ) [A,B](1<=A<=B<=1,000,000) [A,B](1<=A<=B<=1,000,000)
如果要满足奶牛们的要求,并且每天每头奶牛都要被挤过奶,至少需要多少牛棚
每头牛应该在哪个牛棚被挤奶
对于每组数据,可能会有很多可行解,你的程序只需要输出任意一组

输入格式
1 1 1行: 一个单独的整数 N N N,为奶牛的总数
2.. N + 1 2..N+1 2..N+1行: 每行包括 2 2 2个用空格隔开的正整数,第 i + 1 i+1 i+1行的数据描述的是第 i i i头奶牛的产奶时段

输出格式
1 1 1行: 输出一个整数 M M M,表示最少需要的牛棚数
2.. M + 1 2..M+1 2..M+1行: 每行输出一个整数,第 i + 1 i+1 i+1行的整数表示第 i i i头牛被安排到的牛棚的编号

input

5
1 10
2 4
3 6
5 8
4 7

output

4
1
2
3
2
4

题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int n, ans[50050];
struct psx{int st, ed, id;} cow[50050];
bool mycmp(psx a, psx b) { return a.st < b.st; }
priority_queue< int,vector < pair<int, int> >, greater< pair<int, int> > > q; 

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) {
		scanf("%d%d", &cow[i].st, &cow[i].ed);
		cow[i].id = i;
	}
	sort(cow+1, cow+1+n, mycmp);
	int num = 1, p = 0;
	q.push( make_pair(cow[1].ed, 1) );
	ans[1] = 1;
	for(int i = 2; i <= n; i++) {
		if(q.top().first < cow[i].st) {
			p = ans[cow[i].id] = q.top().second;
			q.pop();
			q.push(make_pair(cow[i].ed ,p));
		}
		else {
			q.push(make_pair(cow[i].ed,++num));
			ans[cow[i].id] = num;
		}
	}
	printf("%d\n", q.size());
	for(int i = 1; i <= n; i++)
		printf("%d\n", ans[i]);
	return 0;
}

在这里插入图片描述

Radar Installation

贪心

题目大意:
  Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d
  We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.
  在这里插入图片描述
Input
输入将会有多组数据,每组数据第一行为n (1<=n<=1000),d,n为海岛个数,d为雷达半径,接下来n行,每行两个数描述海岛坐标。

Output
每组数据对应一行,输出最少需要的雷达个数,如果不能满足,则输出-1,具体格式见样例

翻译
假设陆地的海岸线是一条无限延长的直线,海岛是一个个的点,现需要在海岸线上安装雷达,使整个雷达系统能够覆盖到所有的海岛。雷达所能覆盖的区域是以雷达为圆心半径为d的圆,我们用指标坐标系来描述,海岸线就是x轴,现在给出每个海岛的坐标与雷达的半径d,请编写一个程序计算出最少需要多少个雷达才能够将所有海岛全部覆盖?

input

3 2
1 2
-3 1
2 1
1 2
0 2

output

2
1

题解

代码

#include<bits/stdc++.h>
using namespace std;

struct psx{ double l, r; } p[1005];
int n, d, x, y, ans;
bool mycmp(psx a, psx b) {return a.l < b.l;}

int main() {
	while(scanf("%d%d",&n , &d) != EOF){ 
		bool flag = 1;
		for(int i = 1; i <= n; i++) {
			scanf("%d%d", &x, &y);
			if(y > d || !flag) {flag = 0; continue;}
			double xi = sqrt(d*d-y*y);
			p[i].l = x-xi;
			p[i].r = x+xi;
		}
		if(!flag) { printf("-1\n"); continue;}
		ans = 0;
		sort(p+1, p+1+n, mycmp);
		double pos = -9999999;
		for(int i = 1; i <= n; i++) {
			if(p[i].l > pos) { ans++; pos = p[i].r; }
			else pos = min(p[i].r, pos);
		}
		printf("%d\n", ans);
	}
	return 0;
}

在这里插入图片描述

Soldiers

中位数

题目大意:
N soldiers of the land Gridland are randomly scattered around the country. A position in Gridland is given by a pair (x,y) of integer coordinates. Soldiers can move - in one move, one soldier can go one unit up, down, left or right (hence, he can change either his x or his y coordinate by 1 or -1).
The soldiers want to get into a horizontal line next to each other (so that their final positions are (x,y), (x+1,y), …, (x+N-1,y), for some x and y). Integers x and y, as well as the final order of soldiers along the horizontal line is arbitrary.
The goal is to minimise the total number of moves of all the soldiers that takes them into such configuration.
Two or more soldiers must never occupy the same position at the same time.
这个题目的意思是给你n个士兵在棋盘里的坐标,要你将他们排成连续的一行(即与x轴平行),问你最少要将这些士兵移动多少步。

Input
The first line of the input contains the integer N, 1 <= N <= 10000, the number of soldiers. The following N lines of the input contain initial positions of the soldiers : for each i, 1 <= i <= N, the (i+1)st line of the input file contains a pair of integers x[i] and y[i] separated by a single blank character, representing the coordinates of the ith soldier, -10000 <= x[i],y[i] <= 10000.

Output
The first and the only line of the output should contain the minimum total number of moves that takes the soldiers into a horizontal line next to each other.

input

5
1 2
2 2
1 3
3 -2
3 3

output

8

题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll ans = 0;
int x[10010]={}, y[20010]={};
int mid = 0, n;

int main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; i++) 
		scanf("%d%d", &x[i], &y[i]);
	sort(x+1, x+1+n);
	sort(y+1, y+1+n);
	int mid = y[n/2];
	for(int i = 1; i <= n; i++)
		ans += abs(y[i]-mid);
	for(int i = 1; i <= n; i++)
		x[i] = x[i] - i;
	sort(x+1, x+1+n);
	mid = x[n/2];
	for(int i = 1; i <= n; i++)
		ans += abs(x[i]-mid);
	printf("%lld", ans);
	return 0;
}

在这里插入图片描述

奇数码问题

逆序对

题目大意:
你一定玩过八数码游戏,它实际上是在一个33的网格中进行的,1个空格和1~8这8个数字恰好不重不漏地分布在这33的网格中。
例如:

5 2 8
1 3 _
4 6 7

在游戏过程中,可以把空格与其上、下、左、右四个方向之一的数字交换(如果存在)。
例如在上例中,空格可与左、上、下面的数字交换,分别变成:

5 2 8       5 2 _      5 2 8
1 _ 3       1 3 8      1 3 7
4 6 7       4 6 7      4 6 _

奇数码游戏是它的一个扩展,在一个 n ∗ n n*n nn的网格中进行,其中 n n n为奇数,1个空格和1~nn-1这nn-1个数恰好不重不漏地分布在n*n的网格中。空格移动的规则与八数码游戏相同,实际上,八数码就是一个n=3的奇数码游戏。

现在给定两个奇数码游戏的局面,请判断是否存在一种移动空格的方式,使得其中一个局面可以变化到另一个局面。

输入
多组数据,对于每组数据:

第1行一个整数n,n< 500,n为奇数。

接下来n行每行n个整数,表示第一个局面。

接下来n行每行n个整数,表示第二个局面。

局面中每个整数都是0~n*n-1之一,其中用0代表空格,其余数值与奇数码游戏中的意义相同,保证这些整数的分布不重不漏。

输出
对于每组数据,若两个局面可达,输出TAK,否则输出NIE。 
input

3
1 2 3
0 4 6
7 5 8
1 2 3
4 5 6
7 8 0
1
0
0

output

TAK
TAK

题解

代码

#include<bits/stdc++.h>
using namespace std;

int b[250010], a[250010], n, i;
long long cnt1, cnt2, cnt;
bool flag = 0;

int work(int l, int r) {
	if(l == r) return 0;
	int mid = (l+r) /2;
	work(l, mid);
	work(mid+1, r);
	int o = l-1, p = l, q = mid+1;
	while(p <= mid+1 && q <= r+1) {
		if(p == mid+1 && q == r+1) break;
		if( (a[p] <= a[q] && p <= mid) || q == r+1) 
			b[++o] = a[p], p++;
		if( (a[q] <  a[p] && q <= r)   || p == mid+1)
			b[++o] = a[q], q++, cnt += max((mid-p+1), 0);
	}
	for(int i = l; i <= r; i++)	  a[i] = b[i];
	return cnt & 1;
}

void init() {
	i = 1; flag = 0;
	while(i < n) {
		scanf("%d", &a[i]);
		if(a[i] != 0) i++;
		else flag = 1;
	}
	if(!flag) scanf("%d", &a[n+1]);
}

int main() {
	while(scanf("%d", &n) != EOF) {
		n *= n;
		if(n == 1) { 
			scanf("%d%d", &a[1], &a[2]); 
			a[1] == a[2] ? puts("TAK") : puts("NIE");
			continue;
		}
		cnt1 = cnt2 = 0;
		init(); cnt = 0; cnt1 = work(1, n-1);
		init(); cnt = 0; cnt2 = work(1, n-1);
		if(cnt2 == cnt1) puts("TAK");
		else             puts("NIE");
	}
	return 0;
} 

在这里插入图片描述

Ultra-QuickSort

逆序对

题目大意:
In this problem, you have to analyze a particular sorting algorithm. The algorithm processes a sequence of n distinct integers by swapping two adjacent sequence elements until the sequence is sorted in ascending order. For the input sequence 9 1 0 5 4 ,

Ultra-QuickSort produces the output 0 1 4 5 9 .

Your task is to determine how many swap operations Ultra-QuickSort needs to perform in order to sort a given input sequence. 题目大概意思:实质上就是求一个数列的逆序数。而其中我们可以运用归并排序的过程来求解,也就是将问题转化为将一个无序数列归并排序了。归并排序的思想,就是将数列不断的分割成小得足够能求解的子数列,求解后再把子答案合并成原始问题的答案。

Input

The input contains several test cases. Every test case begins with a line that contains a single integer n < 500,000 – the length of the input sequence. Each of the the following n lines contains a single integer 0 ≤ a[i] ≤ 999,999,999, the i-th input sequence element. Input is terminated by a sequence of length n = 0. This sequence must not be processed.

输入包含多组数据。每组数据第一行包含一个正整数N,接下来N行用以描述这个序列。数据以N=0结束。 数据范围参看英文题面。

Output

For every input sequence, your program prints a single line containing an integer number op, the minimum number of swap operations necessary to sort the given input sequence.

input

5
9
1
0
5
4
3
1
2
3
0

output

6
0

题解

代码

#include<bits/stdc++.h>
using namespace std;

int b[500010], a[500010], n, p;
long long cnt = 0;

void work(int l, int r) {
	if(l == r) return;
	int mid = (l+r) /2;
	work(l, mid);
	work(mid+1, r);
	int o = l-1, p = l, q = mid+1;
	while(p <= mid+1 && q <= r+1) {
		if(p == mid+1 && q == r+1) break;
		if( (a[p] <= a[q] && p <= mid) || q == r+1) 
			b[++o] = a[p], p++;
		if( (a[q] <  a[p] && q <= r)   || p == mid+1)
			b[++o] = a[q], q++, cnt += max((mid-p+1), 0);
	}
	for(int i = l; i <= r; i++)	  a[i] = b[i];
}

int main() {
	scanf("%d", &n);
	while(n) {
		cnt = 0;
		for(int i = 1; i <= n; i++) 
			scanf("%d", &a[i]);
		work(1, n);
		printf("%lld\n", cnt);
		scanf("%d", &n);
	}
	return 0;
} 

在这里插入图片描述

Sumdiv

分治

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const ll mod = 1e9+7;
ll mul(ll a,ll b){ll res=1;while(b){if(b&1) res=res*a%mod;a=a*a%mod;b>>=1;}return res%mod;}
ll sum(ll p, ll c) {
	if(c == 0) return 1;
	if(c & 1) return (1+mul(p,(c+1)/2)) * sum(p,(c-1)/2) %mod;
	else      return ( (1+mul(p,c/2)) * sum(p,c/2-1) %mod + mul(p,c) ) %mod;
}
ll a, b, ans = 1;

int main() {
	scanf("%lld%lld", &a, &b);
	if(a == 0) { puts("0"); return 0;}
	for(ll i = 2; i <= a; i++) {
		if(a % i) continue;
		ll c = 0;
		while(!(a%i)) c++, a /= i;
		ans = (ans * sum(i, b*c)) % mod;  
	}
	printf("%lld", ans);
	return 0;
}
 

在这里插入图片描述

国王游戏

贪心,高精度

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

struct bignum{int len, num[50010];} sum,maxx,c;

int n, a, b;
struct psx{int a, b;} p[1010];
bool mycmp(psx a, psx b) { return a.a*a.b < b.a*b.b; }

void mul(int b)  {
	for(int i = 1; i <= sum.len; i++) 
		sum.num[i] *= b;
	sum.len += 20;
	for(int i = 1; i <= sum.len; i++) {
		if(sum.num[i] >= 10)
			sum.num[i+1] += sum.num[i] / 10;
		sum.num[i] %= 10;
	}
	while(sum.num[sum.len]) sum.len--;
}

bignum div(int b)  {
    bignum d;
    for(int t = 0, i = sum.len; i >= 1; i--) {
        t = t*10 + sum.num[i];
        d.num[i] = t / b; 
        t %= b; 
    }
    int len = sum.len;
    while(!d.num[len] && len > 1) len--;
    d.len = len;
    return d; 
}

bignum comp(bignum a, bignum b)  {
	if(a.len > b.len) return a;
	if(a.len < b.len) return b;
	for(int i = a.len; i >= 1; i--) {
		if(a.num[i] > b.num[i])  return a;
		if(a.num[i] < b.num[i])  return b;
	} 
	return a;
}

int main() {
	scanf("%d%d%d", &n, &a, &b);
	for(int i = 1; i <= n; i++)
		scanf("%d%d", &p[i].a, &p[i].b);
	sort(p+1, p+1+n, mycmp);
	maxx.len = 1;  maxx.num[1] = 0;
	sum. len = 1;  sum. num[1] = 1;
	mul(a);
	for(int i = 1; i <= n; i++) {
		c = div(p[i].b);
		maxx = comp(maxx, c);
		mul(p[i].a);
	}
	for(int i = maxx.len; i >= 1; i--) 
		printf("%d", maxx.num[i]); 
	return 0;
}

在这里插入图片描述

AAAAA

HHHHH

题目大意:
  
input


output


题解

代码


在这里插入图片描述

AAAAA

HHHHH

题目大意:
  
input


output


题解

代码


在这里插入图片描述

Best Cow Fence

二分

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long 
using namespace std;

int n, f;
int a[100010], b[100010];
double sum[100010];
int main(){
	scanf("%d%d", &n, &f);
	for(int i = 1; i <= n; i++)
		scanf("%d", &a[i]);
	double l = -1e6, r = 1e6;
	double eps = 1e-5;
	while(r - l > eps){
		double mid = (l + r) / 2;
		for(int i = 1; i <= n; i++)
			b[i] = a[i] - mid;
		for(int i = 1; i <= n; i++)
			sum[i] = sum[i-1] + b[i];
		double ans = -1e10;
		double minval = 1e10;
		for(int i = f; i <= n; i++){
			minval = min(minval, sum[i - f]);
			ans = max(ans, sum[i] - minval);
		}
		if(ans >= 0) l = mid;
		else r = mid;
	}
	printf("%d\n", int(r*1000));
	return 0;
}

在这里插入图片描述

糖果传递

中位数

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

int n;
ll a[1000010], sum[1000010];

int main() {
	scanf("%d", &n);
	ll ans = 0;
	for(int i = 1; i <= n; i++) {
		scanf("%lld", &a[i]);
		ans += a[i];
	}
	ans /= n; 
	for(int i = 1; i <= n; i++) {
		a[i] -= ans;
		sum[i] = sum[i-1] + a[i];
	}
	sort(sum+1, sum+1+n);
	ans = 0;
	for(int i = 1; i <= n; i++)
		ans += abs(sum[i]-sum[n/2+1]);
	printf("%lld", ans);
	return 0;
}

在这里插入图片描述

防线

二分

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const ll M = 2e5+10;
struct psx { ll s, e, d;} f[M];
ll n, T;

bool mycmp(psx a, psx b) {return a.s==b.s ? a.d<b.d : a.s<b.s;}
bool ask(ll l, ll r) {
	ll ans = 0;
	for(ll i = 1; i <= n; i++) {
		if(f[i].s > r) break;
		ans += ( min(f[i].e, r) - f[i].s) / f[i].d +1;
	}
	return ans&1;
}

ll get(int l) {
	ll ans = 0;
	for(int i = 1; i <= n; i++) {
		if(f[i].e < l) continue;
		if(f[i].s > l) break;
		if( (l - f[i].s) % f[i].d == 0) ans++;
	}
	return ans;
}

int main() {
	scanf("%lld", &T);
	while( T-- ) {
		bool p = 0;
		scanf("%lld", &n);
		ll l = 0, r = 0;
		for(ll i = 1; i <= n; i++) {
			scanf("%lld%lld%lld", &f[i].s, &f[i].e, &f[i].d);
			r = max(r, f[i].e);
		}
		sort(f+1, f+1+n, mycmp);
		while(l < r) {
			ll mid = (l+r)/2;
			if(ask(l, mid)) { r = mid; p = 1;}
			else l = mid+1;
		}
		if(p) printf("%lld %lld\n",l, get(l));
		else printf("There's no weakness.\n");
	}	
	return 0;
}

在这里插入图片描述

起床困难综合征

位运算

题目大意:
  
input


output


题解

代码

#include<bits/stdc++.h>
#define ll long long
#define memset(x) memset(x, 0, sizeof(x))
using namespace std;

int n, m;
int num[100010][3];
string str;

int calc(int bit, int now){
	for(int i = 1; i <= n; i++){
		int x = (num[i][2] >> bit) & 1;
		if(num[i][1] == 1) now &= x;
		else if(num[i][1] == 2) now |= x;
		else now ^= x;
	}
	return now;
}

int main(){
	scanf("%d%d", &n, &m);
	for(int i = 1; i <= n; i++){
		cin>>str;
		int a;  scanf("%d", &a);
		if(str[0] == 'A')      num[i][1] = 1;
		else if(str[0] == 'O') num[i][1] = 2;
		else if(str[0] == 'X') num[i][1] = 3;
		num[i][2] = a;
	}
	int val = 0, sum = 0;
	for(int bit = 29; bit >= 0; bit--){
		int ans0 = calc(bit, 0);
		int ans1 = calc(bit, 1);
		if(val + (1 << bit) <= m && ans0 < ans1)
		   val += 1 << bit, sum += ans1 << bit;
		else sum += ans0 << bit;
	}
	printf("%d\n", sum);
	return 0;
}

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值