记 2024.4.21 Sick Day 1&&贪心专项练 Part1
Sick Day 部分每天 道题。
P2629
好消息,坏消息
题目描述
Uim 在公司里面当秘书,现在有 条消息要告知老板。每条消息有一个好坏度,这会影响老板的心情。告知完一条消息后,老板的心情等于老板之前的心情加上这条消息的好坏度。最开始老板的心情是 ,一旦老板心情到了 以下就会勃然大怒,炒了 Uim 的鱿鱼。
Uim 为了不被炒,提前知道了这些消息(已经按时间的发生顺序进行了排列)的好坏度,希望知道如何才能不让老板发怒。
Uim 必须按照事件的发生顺序逐条将消息告知给老板。不过 Uim 可以使用一种叫 “倒叙” 的手法,例如有 条消息,Uim 可以按 (事件编号)这种顺序通报。
他希望知道,有多少个 ,可以使从 号事件开始通报到 号事件然后再从 号事件通报到 号事件可以让老板不发怒。
输入格式
第一行一个整数 (),表示有 个消息。
第二行 个整数,按时间顺序给出第 条消息的好坏度 ()。
输出格式
一行一个整数,表示可行的方案个数。
样例 #1
样例输入 #1
4
-3 5 1 2
样例输出 #1
2
提示
【样例解释】
通报事件的可行顺序(用编号表示)为 或 (分别对应 和 )
通报事件的可行顺序(用好坏度表示)为 或
【数据范围】
对于 的数据,;
对于 的数据,;
对于 的数据,。
这种啊,一般都是前缀和,不过我们可以不用单调队列做这题。
由于我们是希望进行累加的过程中没有负数对吧。所以对于一个断点 我们怎么判断它在累加的过程中有没有负数呢?我们可以收集从左往右的前缀和最小值,如果要知道 至 的过程中的最小值,就很容易计算了,,而 至 ,。
Code
#include <iostream>
#define int long long
using namespace std;
const int N=1e7+10;
int sum[N],n,p[N],pr[N],ans;
signed main()
{
cin>>n;p[0]=0x3f3f3f3f3f3f3f3f,pr[n+1]=0x3f3f3f3f3f3f3f3f;
for(int i=1;i<=n;i++) cin>>sum[i],sum[i]+=sum[i-1],p[i]=min(p[i-1],sum[i]);
for(int i=n;i>=1;i--) pr[i]=min(pr[i+1],sum[i]);
for(int i=1;i<=n;i++) if(pr[i]-sum[i-1]>=0&&p[i-1]+sum[n]-sum[i-1]>=0) ans++;
cout<<ans;
return 0;
}
P2589
[ZJOI2006] 碗的叠放
题目描述
小H有n个碗需要放进橱柜,她希望将他们叠起来放置。你知道每个碗都是规则的圆柱体,并且都是上宽下窄,你已经测量出了每个碗的两个半径及高,请你帮小H找出一种叠放顺序,使得叠放出来的碗堆的高度尽量小,比如:

输入格式
第一行一个整数n,表示碗的数目。以下n行,每行三个整数h,r1,r2。分别表示碗高及两个半径。其中r1<r2。
输出格式
仅一个数,表示最小的高度。答案四舍五入取整。
样例 #1
样例输入 #1
3
50 30 80
35 25 70
40 10 90
样例输出 #1
55
提示
数据范围:100%数据满足n<=9。所有输入的数绝对值不超过1000。
恶心推式子,注意想式子到底有没有推全,以及式子的正确性。
P2396
[POI2010] GIL-Guilds
题目描述
King Byteasar faces a serious matter.
Two competing trade organisations, The Tailors Guild and The Sewers Guild asked, at the same time, for permissions to open their offices in each town of the kingdom.
There are
towns in Byteotia.
Some of them are connected with bidirectional roads.
Each of the guilds postulate that every town should:
have an office of the guild, or be directly connected to another town that does.
The king, however, suspects foul play. He fears that if there is just a single town holding the offices of both guilds, it could lead to a clothing cartel.
For this reason he asks your help.
给一张无向图,要求你用黑白灰给点染色,且满足对于任意一个黑点,至少有一个白点和他相邻;对于任意一个白点,至少有一个黑点与他相邻,对于任意一个灰点,至少同时有一个黑点和白点和灰点与他相邻,问能否成功
输入格式
Two integers, n(<=200000) and m(<=500000), are given in the first line of the standard input. These denote the number of towns and roads in Byteotia, respectively.
The towns are numbered from 1 to n.
Then the roads are given as follows: the input line no. i+1 describes the i-th road;
输出格式
Your program should print out one word in the first line of the standard output:
TAK (yes in Polish) - if the offices can be placed in towns according to these rules, or NIE (no in Polish) - in the opposite case.
If the answers is TAK, then the following nlines should give an exemplary placement of the offices. Thus the line no. i+1 should hold:
the letter K if there should be an office of The Tailors Guild in the town i, or the letter S if there should be an office of The Sewers Guild in the town i, or the letter N if there should be no office in the town i.
样例 #1
样例输入 #1
7 8
1 2
3 4
5 4
6 4
7 4
5 6
5 7
6 7
样例输出 #1
TAK
K
S
K
S
K
K
N
提示
题目spj贡献者@mengbierr
发现灰点没用,放灰点的地方放白黑点都可以,于是考虑BFS染色,因为只要两侧之一有异色即可,所以就像二分图匹配那样匹配就可以了。而且除了有单独点的情况,其它的情况都可以染,因为条件比二分图松。
注意发现题目中无用的操作,以及与以往知识的联系,不要太早否掉想法。
Code
#include <iostream>
#include <queue>
#include <cstring>
#define int long long
#define get(x) 3-x;
using namespace std;
const int N=1e6*4+10;
int color[N],st[N],vis[N];
int h[N],e[N],ne[N],idx;
int n,m;
void add(int a,int b)
{
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
void dfs(int u,int c)
{
color[u]=c;
queue<int> q;
q.push(u);
while(q.size())
{
auto t=q.front();
q.pop();
if(st[t]) continue;
st[t]=1;
for(int i=h[u];i!=-1;i=ne[i])
{
int j=e[i];
if(!color[j]) q.push(j),color[j]=get(color[t]);
}
}
}
signed main()
{
memset(h,-1,sizeof h);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
add(x,y);
add(y,x);
vis[x]=vis[y]=1;
}
bool flag=1;
for(int i=1;i<=n&&flag;i++)
{
if(!vis[i]) flag=0;
}
if(flag)
{
for(int i=1;i<=n;i++) if(!st[i]) dfs(i,1);
puts("TAK");
for(int i=1;i<=n;i++) if(color[i]==1) cout<<'K'<<endl; else cout<<'S'<<endl;
}
else puts("NIE");
return 0;
}
贪心专项练部分
P1016
[NOIP1999 提高组] 旅行家的预算
题目描述
一个旅行家想驾驶汽车以最少的费用从一个城市到另一个城市(假设出发时油箱是空的)。给定两个城市之间的距离 、汽车油箱的容量 (以升为单位)、每升汽油能行驶的距离 、出发点每升汽油价格和沿途油站数 ( 可以为零),油站 离出发点的距离 、每升汽油价格 ()。计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution。
输入格式
第一行,,,,,。
接下来有 行。
第 行,两个数字,油站 离出发点的距离 和每升汽油价格 。
输出格式
所需最小费用,计算结果四舍五入至小数点后两位。如果无法到达目的地,则输出 No Solution。
样例 #1
样例输入 #1
275.6 11.9 27.4 2.8 2
102.0 2.9
220.0 2.2
样例输出 #1
26.95
提示
,其余数字 。
NOIP1999 普及组第三题、提高组第三题
考虑与 CSP-J 2023 t2 一样的做法,不过是浮点数,难处理,而且每个站点与起始点的距离不一定单调递增,所以需要排序,还有有油箱容量的限制,需要特判,如果接满油不够到下一个更便宜的站点,那么就接满油,而不是接刚好到达能到的最远站点(最远站点的价格更贵,因为果接满油不够到下一个更便宜的站点)。这就引入了多的不是整路的油,于是我们每次都要减去那些油能可以过的路程,油箱也要算上那些油,于是油箱容量减低。
代码写得很狗屎
Code
#include <iostream>
#include <algorithm>
using namespace std;
const int N=510;
double kk,c;
int n;
struct sta
{
double d,p;
}a[N];
bool cmp(sta x,sta y)
{
return x.d<y.d;
}
int main()
{
//freopen("P1016_5.in","r",stdin);
cin>>a[0].d>>kk>>c>>a[0].p>>n;
if(c==0)
{
puts("No Solution");
return 0;
}
a[n+1].d=a[0].d;
a[0].d=0;
for(int i=1;i<=n;i++) cin>>a[i].d>>a[i].p;//,cout<<a[i].d<<' '<<a[i].p<<endl;;
sort(a,a+1+n,cmp);
double ans=0,yu=0;
for(int i=0;i<=n;i++)
{
int k=i+1;
double res=0;
while(a[i].p<a[k].p&&k<=n&&(a[k].d-a[i].d-yu)/c<=kk-yu/c) k++;
if(k==i+1&&!((a[k].d-a[i].d-yu)/c<=kk))
{
puts("No Solution");
return 0;
}
double tmp=yu;
if(!((a[k].d-a[i].d-yu)/c<=kk-yu/c))
{
k--;
tmp=c*(kk-(a[k].d-a[i].d-yu)/c);
res=kk*a[i].p;
ans+=res;
yu=tmp;
i=k-1;
continue;
}
//cout<<"!!"<<a[k].d<<" "<<a[i].d<<' '<<k<<' '<<i<<' '<<a[i].p*(a[k].d-a[i].d)/c<<endl;
res=a[i].p*(a[k].d-a[i].d-yu)/c;
ans+=res;
i=k-1;
yu=0;
}
printf("%.2lf",ans);
return 0;
}

浙公网安备 33010602011771号