第二周总结
文章目录
内容概括
涉及算法
模拟,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个随机数里找.
有这么一个结论:随机两个正整数互质的概率为 那么只要对前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;
}