2021.08.26 膜你赛
fish
Description
\(LYK\) 家里有 \(n\) 只猫。
这一天,\(LYK\) 安排了 \(m\) 条鱼给这些猫吃。特别地,第 \(i\) 只猫吃一条鱼需要花费 \(a[i]\) 的时间。且一只猫在同一时间最多只会吃一条鱼,且不会有多只猫吃同一条鱼。在第 \(0\) 时刻,\(LYK\) 给每只猫一条鱼。每当有一只猫吃完鱼时,如果此时还有鱼,它会立刻吃下一条鱼。特别地:如果有 \(k\) 只猫在同一时刻一起吃完了鱼,且此时剩下的鱼的个数不足 \(k\),吃的快的猫(即 \(a[i]\) 较小的猫)会优先吃鱼。
\(LYK\) 想知道经过 \(x\) 个时间后,有多少条鱼还没被吃过,以及有多少鱼已经被吃了一部分了(也就是说还没吃完,但已经被吃过了)。
Solution
一开始想着如果直接枚举的话肯定会炸,想着复杂度应该是 \(O(n)\) 的,然后手模样例,似乎发现了一些规律,修修改改过了大样例就跑了,没写对拍。没法证明这东西的正确性,但是好像真的有漏洞,然后就得了60分。
正解大概是开一个优先队列,将吃完鱼的时间当做第一关键字,将猫吃鱼的时间做第二关键字,每次从堆顶取出吃完鱼时间最小的,看是否达到的我们需要的时间,到了的话就跳出,否则吃一条鱼,放进去。因为可能有同时吃完的可能,将队列里吃完的请出去,剩下的就是吃了,但没吃完的。
因为优先队列是大根堆,所以填进去的是负数。
Code
/*
* @Author: smyslenny
* @Date: 2021.08.26
* @Title: fish
* @Main idea:模拟
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
using namespace std;
const int mod=998244353;
const int M=1e5+5;
int n,m,x,a[M];
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
int res;
priority_queue<pair<int,int> > q;
signed main()
{
// freopen("fish.in","r",stdin);
// freopen("fish.out","w",stdout);
m=read(),n=read(),x=read();
for(int i=1;i<=n;i++) a[i]=read();
// sort(a+1,a+1+n);//排序不会对答案有影响
m-=n;//先减去第一次的
for(int i=1;i<=n;i++)
q.push(make_pair(-a[i],-a[i]));//第一次
while(!q.empty())
{
int fir=-q.top().first,sec=-q.top().second;//第一位吃完的时间,第二位存每只猫吃鱼的时间
if(fir>=x)//当前的吃完的时间比规定的时间大,后面的肯定也吃不完
break;
q.pop();
if(m) q.push(make_pair(-sec-fir,-sec)),m--;//新吃一条鱼
}
while(!q.empty() && (-q.top().first)<=x) q.pop();//剩下的可能有同一时间吃完的
res=(int)q.size();
printf("%lld %lld\n",m,res);
}//
/*
88 11 49
22 20 18 19 9 24 22 23 12 9 1
8 3 5
1 3 4
2 2 3
1 100
*/
bag
Description
\(Ariel\) 有一个容量为 \(m\) 的背包,总共有 \(n\) 个物品,每个物品有它的体积 \(p_i\),价值 \(v_i\),从中选若干物品使得它们的体积和不超过 \(m\),且价值之和最大。
但是这个问题过时了!
接下来是这个问题的加强版:
\(Ariel\) 有 \(m\) 块钱,总共有 \(n\) 个物品,每个物品有它的价格 \(p_i\),参数 \(q_i\),价值 \(v_i\)。\(Ariel\) 可以用某个顺序来购物。它想买一个物品当且仅当它还剩下的钱不小于该物品的参数 \(q_i\)。之后为了买这个物品,它的总钱数会减少 \(p_i\),相应的,得到的价值总和会增加 \(v_i\)。每个物品最多买一次,\(Ariel\) 可以随便安排一个购物顺序,它想使得满足购物要求的前提下得到的价值之和尽可能高。
题目中说了是01背包的加强版,所以先敲上了01背包的板子,加上了限制,但是发现大样例怎么都过不了,开始大力排序,贪心的来说,应该是按照 \(p_i\) 排序的,但是怎么做都跟答案差上100,就直接交了,没想到还有50分,以为就10分的。
正确的排序是按照 \(q_i-p_i\) 从大到小排序。
/*
* @Author: smyslenny
* @Date: 2021.08.26
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <vector>
#define int long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
using namespace std;
const int mod=998244353;
const int M=5e3+5;
struct node{
int p,q,v;
}sz[M];
int n,V,f[M];
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
int Max=-INF;
bool cmp(node a,node b)
{
return a.p-a.q>b.p-b.q;
}
signed main()
{
//freopen("bag.in","r",stdin);
//freopen("bag.out","w",stdout);
n=read(),V=read();
for(int i=1;i<=n;i++)
sz[i].p=read(),sz[i].q=read(),sz[i].v=read();
sort(sz+1,sz+1+n,cmp);
for(int i=1;i<=n;i++)
for(int j=V;j>=sz[i].q;j--)
f[j]=max(f[j],f[j-sz[i].p]+sz[i].v),Max=max(Max,f[j]);
printf("%lld\n",Max);
return 0;
}
/*
10 100
50 100 100
20 50 101
10 10 20
40 30 40
10 50 70
20 60 101
40 50 20
10 10 50
30 20 40
10 10 20
*/
beng
Description
\(Zxsoul\) 身处在一个二维平面。但这个平面快坍塌了!
我们可以想象成这个平面是左上角在 \((-10^{12},10^{12})\) 右下角在 \((10^{12},-10^{12})\) 的一个巨大矩阵。这个矩阵被分割成了若干个 \(1\times 1\) 的格子,一开始这个矩阵的最外层格子都会布满蚂蚁。
每次每只蚂蚁都会繁衍出新的蚂蚁爬向上下左右四个方向。
\(Zxsoul\) 要圈出一块属于自己的领地。一开始它处于某个格子中,它手里有一桶杀虫剂。\(Zxsoul\) 会执行 \(k\) 次操作,每次操作都是向四个方向(用 \(c_i\) 表示)的某个方向走 \(a_i\) 格,在走的过程中它会将杀虫剂倒在所有经过的格子上。并且 \(Zxsoul\) 保证在行走的过程中不会走到这个矩阵
的最外层格子上(即不会走到二维平面的边缘处)。蚂蚁不会繁衍到被喷了杀虫剂的格子上。
\(Zxsoul\) 想知道经过无限长的时间后有多少格子上是没有蚂蚁的。
把走到的点标记一下,然后从外围搜索,能拿到 70 分。
Code
/*
* @Author: smyslenny
* @Date: 2021.08.26
* @Title:
* @Main idea:
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#define ll long long
#define INF 0x3f3f3f3f
#define orz cout<<"LKP AK IOI\n"
#define MAX(a,b) (a)>(b)?(a):(b)
#define MIN(a,b) (a)>(b)?(a):(b)
using namespace std;
const int mod=998244353;
const int M=2e3+5;
int mp[M+10][M+10];
int dx[5]={0,1,-1,0,0};
int dy[5]={0,0,0,1,-1};
int k;
int read()
{
int x=0,y=1;
char c=getchar();
while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
return y?x:-x;
}
int Ans;
queue<pair<int,int> >q;
int bfs()
{
int js=0;
q.push(make_pair(1,1));
js++;
mp[1][1]=1;
while(!q.empty())
{
int X=q.front().first,Y=q.front().second;
q.pop();
for(int i=1;i<=4;i++)
{
int nx=X+dx[i],ny=Y+dy[i];
if(nx<=2005 && nx>=1 && ny<=2005 && ny>=1 && mp[nx][ny]==0)
{
js++;
mp[nx][ny]++;
q.push(make_pair(nx,ny));
}
}
}
return js;
}
int x=1005,y=1005;
int main()
{
// freopen("beng.in","r",stdin);
// freopen("beng.out","w",stdout);
k=read();
mp[x][y]=1;
for(int i=1,st;i<=k;i++)
{
char op;
cin>>op;st=read();
if(op=='U') while(st--) mp[--x][y]++;
if(op=='D') while(st--) mp[++x][y]++;
if(op=='R') while(st--) mp[x][++y]++;
if(op=='L') while(st--) mp[x][--y]++;
}
printf("%d\n",M*M-bfs());
return 0;
}
/*
7
R 10
D 2
L 7
U 9
D 2
R 3
D 10
*/