欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

第二周总结

程序员文章站 2024-01-29 10:33:40
...

内容概括

涉及算法

模拟,01分数规划,思维

题数

3

相关算法

模拟

洛谷OJ P1538 迎春舞会之数字舞蹈

原题链接

题意: 打印数字图形(输入一串只包含0-9的字符串) 边长为k

思考过程及相关解法:并没有想到优秀的模拟方法,于是参考了题解的方法-_-

考虑到组成这些数字最多需要7条线 于是把十个数的七条线按位置存放起来,即代码中的预处理部分s[10],存放的是单位大小的数字的相对位置

如:3的图形

 - 
  |
 -
  |
 -               (orz好丑

之后枚举七条边 在处理最右边的竖线时交由处理左边竖线时同时处理.所以在2和5时不作处理

横线位置刚好是3的倍数

剩余的枚举所有数进行填补

具体参考如下代码

参考代码:

#include <iostream>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;

char s[10][8] = {"-|| ||-","  |  | ","- |-| -","- |- |-"," ||- | ","-| - |-","-| -||-","- |  | ","-||-||-","-||- |-"}; 
char st[550];
int main()
{
	int k;scanf("%d",&k);
	scanf("%s",st);
	int len = strlen(st);
	for (int i = 0; i < 7; ++i){
		if (i == 2 || i == 5) continue; //最右边处理由最左边时来处理 
		if (i % 3 == 0){ //横线 
			for (int j = 0; j < len; ++j){
				printf(" ");
				for (int o = 0; o < k; ++o){
					printf("%c",s[st[j] - '0'][i]);
				}
				printf("  ");
			}
			printf("\n");
		}else{//竖线部分 
			for (int p = 0; p < k; ++p){ //k行 
					for (int j = 0; j < len; ++j){ //处理每行 
						printf("%c",s[st[j]-'0'][i]);
						for (int o = 0; o < k; ++o){//中间空格 
							printf(" ");
							}
						printf("%c ",s[st[j]-'0'][i+1]); //补右边位置 
					}
				printf("\n"); 
			}
			
		}
	} 
	return 0;
}

01分数规划

牛客网暑期ACM多校训练营(第五场) A

原题链接

题意:一共n门课程,每门课程有一个成绩s[i]和学分c[i[,最终成绩为第二周总结

要求去掉k门课程使得最终成绩最大.

思考过程及相关解法:当时最多想到了二分枚举答案,但不知道如何处理,学习了01分数规划后,发现将乘到右边,既然我们枚举的是答案,那么将答案看做自变量,

设 f® = $ \sum s[i]c[i] -r \sum s[i] $

这是一个斜率为负的直线 当f®为0时的r就是我们需要的答案,所以当f®>0时,仍需要更大的r,此时二分l =mid,f®<0,则r = mid,在check函数里选取可以使用的学科判断当前选取的r值是大是小.

01分数规划参考博客:http://www.knowsky.com/957231.html

参考代码:

#include <iostream>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const int MAXN = 1e5+11;
int c[MAXN],s[MAXN];
int id[MAXN];
bool vis[MAXN];
int n,k;
double A;
inline bool cmp(const int& a,const int& b){
	return (s[a]*c[a]-A*s[a]) < (s[b]*c[b]-A*s[b]);
}
bool check(double D){
	for (int i  = 0; i < n; ++i) id[i] = i,vis[i] = 0;
	A = D;
	nth_element(id, id + k, id + n,cmp);
	for (int i = 0; i < k; ++i){
		double d = s[id[i]]*(c[id[i]]-D);
		if (d < 0) vis[id[i]] = 1;
	}
	double sumup = 0,sumd = 0;
	for (int i = 0; i < n; ++i){
		if (!vis[i]){
			sumup += c[i]*1.*s[i];
			sumd += s[i]; 
		}
	}
	return sumup/sumd > D; 
}

int main()
{
	
	scanf("%d%d",&n,&k);
	for (int i = 0; i < n; ++i){
		scanf("%d",&s[i]);
	}
	for (int i = 0; i < n; ++i){
		scanf("%d",&c[i]);
	}
	double l = 0,r = 1e3;
	for  (int i = 0; i < 50; ++i){
		double mid = (l + r)/2;
		if (check(mid)) l = mid;
		else r = mid;
	}
	printf("%.7f\n",l);
	return 0;
}

思维

牛客网暑期ACM多校训练营(第五场) J

原题链接

题意:n个学生订房间,有双人间,三人间两种房间,价格分别是p2,p3,求订房间的最小花费

思考过程及题解:问题在于处理多出来的人,分别对于选二人间和1三人间多出来的一个人1进行判断,因为前一个房间的策略可以和剩余这个人重新按最优策略进行分配

参考代码:

#include <iostream>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
const int MAXN = 1e5+11;


int main()
{
	LL n,p2,p3;
	LL sum = 0;
	scanf("%lld%lld%lld",&n,&p2,&p3);
	if (3*p2 <= 2*p3){
		sum += n/2*p2;
		if (n%2 == 1 && n/2) sum += min(p3-p2,p2);
		else if (n == 1) sum += min(p2,p3);
	}else{
		sum = n/3*p3;
		if (n%3 == 2) sum += min(p2,p3);
		if (n%3 == 1 && n != 1) sum += min(min(2*p2-p3,p2),p3);
		else if (n == 1) sum += min(p2,p3);
	}
	printf("%lld\n",sum);
	return 0;
}

概率论 枚举 unsigned

牛客网暑期ACM多校训练营(第六场)J

原题链接

题意:使用题中给的函数生成n个数,在这n个数里找两个数,要求这两个数的lcm最大.

思考过程及题解:首先要知道这个函数差不多相当于是个随机数生成函数,那么就是在n个随机数里找.

有这么一个结论:随机两个正整数互质的概率为6/π26/\pi^2 那么只要对前k大的数进行暴力即可,大约在17个数之间即可找到两个互质的,那么k取一个较小值就可以了

生成数据函数一定要用unsigned 而不能用unsigned long long ,否则会导致生成数据出错

参考代码:

#include <iostream>
#include <map>
#include <cstdio>
#include <string>
#include <cstring>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef unsigned long long ll;
const int MAXN = 1e5+11;
unsigned x,y,z;

unsigned ax[10000005];
int n;
unsigned tang(){
	unsigned t;
	x ^= x << 16;
	x ^= x >> 5;
	x ^= x << 1;
	t = x;
	x = y;
	y = z;
	z = t^x^y;
	return z;
}
unsigned gcd(unsigned a,unsigned b){
	return !b?a:gcd(b,a%b);
}
ll lcm(unsigned a,unsigned b){
	return a/gcd(a,b)*(ll)b;
}
int main()
{
	int t;
	scanf("%d",&t);
	int Case = 1;
	while (t--){
		scanf("%d%u%u%u",&n,&x,&y,&z);
		int tt = min(n,100);
		for (int i = 0; i < n; ++i){
			ax[i] = tang();
		}
		nth_element(ax,ax+n-tt,ax+n);
		ll mx = 0;
		ll tm;
		for (int i = n-tt; i < n; ++i){
			for (int j  = i + 1; j < n; ++j){
				tm = lcm(ax[i],ax[j]);
				if ( tm > mx) mx = tm;
			}
		}
		printf("Case #%d: %llu\n",Case++,mx);
	}
	return 0;
}