第二周总结

内容概括

涉及算法

模拟,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[,最终成绩为img

要求去掉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 / π 2 6/\pi^2 6/π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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值