2021 UPC 第十五场
文章目录
前言
这场模拟思维题多,其实也是因为其他的题看一眼就知道不会,而且那个a题数据到底是什么,上来就被卡,还好重写一遍过了。
C 采药(01背包)
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带 到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时 间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
模板题,不多赘述了
#include <bits/stdc++.h>
//#define maxn 20001
using namespace std;
int dp[101][1001];
int w[101],v[101];
int main()
{
int n,m,k;
cin >> m >> n;
for(int i=1;i<=n;i++)
{
cin >> w[i] >> v[i];
}
for(int i=1;i<=n;i++)
{
for(int j=m;j>=0;j--)
{
if(j>=w[i])
{
dp[i][j]=max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]); //状态转移方程
}
else{
dp[i][j]=dp[i-1][j];
}
}
}
cout << dp[n][m];
return 0;
}
E AtCodeer 和油漆罐(stl集合)
最近买了三个油漆罐。他两天前买的那个是 a ,昨天买的颜色是 b ,他今天买的颜色是 c 。在这里,每个油漆的颜色可以由介于 1 和 100 之间的整数表示,包括。
由于他健忘,他可能买了不止一个相同颜色的油漆罐。数数这些油漆罐中不同颜色的数量,然后告诉他。
约束 1≤a,b,c≤100
题意:就是让你维护一个最大元素数是3的集合,输出元素数
#include <bits/stdc++.h>
//#define maxn 20001
using namespace std;
int ans,tao,x;
int a[11];
int main()
{
set<int>s;
for(int i=0;i<3;i++)
{
scanf("%d",&x);
s.insert(x);
}
printf("%d\n",s.size());
return 0;
}
F AtCodeer 画球(快速幂,组合数学)
一排放置了 N 个球。在鹿的油漆罐的K色中,鹿正在画每一种颜色。出于审美原因,任何两个相邻的球必须涂成不同的颜色。
找到画球的可能方法的数量。
约束 1≤N≤1000 2≤K≤1000
正确答案最多为 2的31次方+1.
题意:可以推出一个公式k*pow(n-1,k-1),次数较大,故考虑使用快速幂来维护防超时(也可能不会超)
#include <bits/stdc++.h>
//#define maxn 20001
using namespace std;
long long ksm(long long k,long long n) //快速幂模板
{
long long ans=1;
while(n)
{
if(n&1) ans=ans*k;
k=k*k;
n>>=1;
}
return ans;
}
int main()
{
int n,k;
scanf("%d%d",&n,&k);
printf("%lld\n",k*ksm(k-1,n-1));
return 0;
}
G AtCodeer 和选举报告(思维)
鹿在电视上看到一份快速的选举结果报告。两位候选人正在竞选:高桥和青木。报告显示两位候选人目前获得的选票数的比率,但不包括实际得票数。AtCoDeer 检查了报告 N 次,当他检查报告时,i-th (1≤i≤N) 的比率为 Ti:Ai。众所周知,每位候选人在第一次检查报告时至少获得一票。
查找两位候选人在 N-1 次检查报告时获得的最小可能的总票数。可以假定,每个候选人获得的选票数永远不会减少。
约束 1≤N≤1000 1≤Ti,Ai≤1000(1≤i≤N) Ti 和 Ai (1≤i≤N) 是共性。
保证正确答案最多为 10的18次方.
思路:其实别被题目吓到,你拿笔算一算模拟一下,具体看代码
#include <bits/stdc++.h>
//#define maxn 20001
using namespace std;
//int a[10001],q,z;
int main()
{
long long int x,y,n,m,a,b;
cin >> n >> x >> y;
for(int i=2;i<=n;i++)
{
long long int c=0,d=0; //先定义好上面两个变量的最小倍增数
cin >> a >> b;
if(a>=x&&b>=y) //输入的a,b满足这个条件时,说明没有化简,就是我们要的原始数据,更新即可
{
x=a,y=b;
continue;
}
if(a<x)
{
c=(x+a-1)/a;
}
if(b<y)
{
d=(y+b-1)/b;
}
long long maxn=max(c,d); //跟着大的倍整数走,注意数据范围
x=a*maxn,y=b*maxn;
}
printf("%lld\n",x+y);
return 0;
}
H AtCoDeer and Rock-Paper(贪心)
tCoDeer the deer and his friend TopCoDeer is playing a game. The game consists of N turns. In each turn, each player plays one of the two gestures, Rock and Paper, as in Rock-paper-scissors, under the following condition:
(※) After each turn, (the number of times the player has played Paper)≤(the number of times the player has played Rock).
Each player’s score is calculated by (the number of turns where the player wins) − (the number of turns where the player loses), where the outcome of each turn is determined by the rules of Rock-paper-scissors.
(For those who are not familiar with Rock-paper-scissors: If one player plays Rock and the other plays Paper, the latter player will win and the former player will lose. If both players play the same gesture, the round is a tie and neither player will win nor lose.)
With his supernatural power, AtCoDeer was able to foresee the gesture that TopCoDeer will play in each of the N turns, before the game starts. Plan AtCoDeer’s gesture in each turn to maximize AtCoDeer’s score.
The gesture that TopCoDeer will play in each turn is given by a string s. If the i-th (1≤i≤N) character in s is g, TopCoDeer will play Rock in the i-th turn. Similarly, if the i-th (1≤i≤N) character of s in p, TopCoDeer will play Paper in the i-th turn.
Constraints
1≤N≤105
N=|s|
Each character in s is g or p.
The gestures represented by s satisfy the condition (※).
思路:贪心,但是注意题目给的限制,能出布尽量出;
#include <bits/stdc++.h>
//#define maxn 20001
using namespace std;
//int a[10001],q,z;
int main()
{
string a;
cin >> a;
int sum=0;
int p=0;
for(int i=0;i<a.size();i++)
{
if(a[i]=='g')
{
if(p>0)
{
sum++;
p--;
}
else
{
p++;
}
}
else
{
if(p>0)
{
p--;
}
else
{
p++;
sum--;
}
}
}
cout << sum << endl;
return 0;
}
K 社交距离 1(模拟,暴力)
一种可怕的新疾病,COWVID-19,已经开始在全世界的奶牛中传播。农夫约翰正设法采取尽可能多的预防措施,以保护他的家免受感染。
农民约翰的谷仓是一个长狭窄的建筑,有N个摊位在一排(2≤N≤105).其中一些摊位目前被奶牛占据,有些是空置的。在阅读了"社会疏远"的重要性后,农民约翰想要最大化D,其中D是最接近的两个被占领的摊位之间的距离。例如,如果停滞点 3 和 8 是最近占用的,则 D=5。
最近有两头新奶牛加入了农夫约翰的牛群,他需要决定他们应该分配哪些以前无人居住的摊位。请确定他如何放置他的两头新奶牛,以便D的生成值仍然尽可能大。农夫约翰不能移动他现有的任何奶牛;他只想给新奶牛分配摊位。
思路:1.二分(不会写)
2.分类讨论,有四种
(1)都放在首或者尾;
(2)都放在最大的空里
(3)都放在最大的空和次大的空里
(4)一个放在头或尾,一个放在最大的空里
这就是94分的做法,要想得100,还得特判没有牛的情况,具体看代码
#include <bits/stdc++.h>
using namespace std;
int n,m,maxn1,maxn2,x,y,df=90000000;
int a[100009],ls,kl,ji,jk;
char c;
int main()
{
cin >> n;
for(int i=1; i<=n; i++)
{
cin >> c;
if(c=='1')
{
m++,a[m]=i;
if(m>1) //非队首
{
df=min(df,a[m]-a[m-1]);
if(a[m]-a[m-1]>=maxn1)
{
maxn2=maxn1;
maxn1=a[m]-a[m-1];
}
else
{
maxn2=max(maxn2,a[m]-a[m-1]);
}
}
}
}
x=min(maxn1/2,maxn2/2); //放中间两个区间里
y=maxn1/3; //放在中间一个区间
if(a[1]>1)
{
kl=min(a[1]-1,maxn1/2);//一个头一个最大区间
x=max(x,kl);
y=max(y,(a[1]-1)/2); //两个放在首
}
if(a[m]<n)
{
ji=min(n-a[m],maxn1/2);//一个尾一个最大区间
x=max(x,ji);
y=max(y,(n-a[m])/2); //两个都放在尾
}
if(a[1]>1&&a[m]<n)
{
ls=min(a[1]-1,n-a[m]); //放首尾
}
jk=max(x,max(y,ls));
if(m==0)
{
cout << n-1;
}
else
{
cout << min(df,jk);
}
return 0;
}
L 社交距离 2(思维)
尽管他尽了最大的努力,让他的N牛(1≤N≤1000)练习"社会疏远",他们中的许多人仍然不幸地感染了这种疾病。奶牛,方便编号1…N, 每个站在沿着一条长路径的不同点 (基本上是一维数线), 牛 i 站在位置 xi 。农民 John 知道有一个半径 R,这样任何站在 R 单位, 包括 R单位远离受感染的牛也会被感染 (然后将感染传递给其他奶牛在 R 单位远离, 等等).
不幸的是, 农民约翰并不完全了解 R 。然而,他知道他的哪头牛被感染了。鉴于这些数据,请确定最初感染该病的奶牛的最低数量。
思路:我们可以先写找到满足现有情况最小传播半径,说白了就是现有未患病到患病得最小距离,之后统计数目即可,此外,我感觉并查集也能做这个题
#include <bits/stdc++.h>
using namespace std;
long long n,a[1000001],x,y,minn=91010101,maxn,sum;
int main()
{
cin >> n;
for(int i=1;i<=n;i++)
{
cin >> x >> y;
maxn=max(maxn,x);
if(!y)
{
a[x]=1;
}
else
{
a[x]=2;
}
}
x=1100000,y=2200000;//别忘了开始可没有x,y
for(int i=1;i<=maxn;i++)
{
minn=min(minn,abs(x-y)-1);
if(a[i]==1)
{
y=i;
}
if(a[i]==2)
{
x=i;
}
}
minn=min(minn,abs(x-y)-1);
x=-1;
for(int i=1;i<=maxn;i++)
{
if(a[i]==2)
{
if(i>x) sum++;
x=i+minn; //注意这个别忘了可以连续传播,而我们要统计的是初代患者
}
}
printf("%d\n",sum);
return 0;
}