Codeforces Round 980 (Div. 2)
Codeforces Round 980 (Div. 2) 总结
A
简单小学算数题。
- 如果 \(b \le a\),直接输出 \(a\)。
- 否则,列方程 \(a-x=b-2x\),\(x=b-a\),输出 \(a-x\),即 \(2a-b\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=1;
int a,b;
void solve()
{
cin>>a>>b;
if(a>=b) cout<<a<<'\n';
else cout<<max(2*a-b,0)<<'\n';
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;
cin>>T;
while(T--) solve();
return 0;
}
B
这道题似乎卡了不少人 qwq。首先,因为每次不知道是不是有一个按钮按完后不出饮料,额外的贡献就产生在这,但是同一个不出的按钮又只会按一次(又不是傻子)。
所以不妨将 \(a\) 排序,从小到大取,每次先把空的按一遍,当然第一轮不计。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int n;
ll k,ans;
ll a[N];
void solve()
{
cin>>n>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
ans=0;
for(int i=1;i<=n;i++)
{
ll t=(a[i]-a[i-1])*(n-i+1);
ans++;
if(k<=t)
{
ans+=k;
break;
}
else
{
k-=t;
ans+=t;
}
}
cout<<ans-1<<'\n';
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int T;
cin>>T;
while(T--) solve();
return 0;
}
C
其实题意就是设计一种 pair
的排序。
严格证明还是要分类讨论:设数对中的最大值为 \(mx\),最小值为 \(mi\),对于两个数对 \(x,y\)
- \(x_{mi} \le y_{mi} , x_{mx} \le y_{mx}\),显然 \(x\) 应该在前面。
- \(x_{mi} \le y_{mi} , y_{mx} \le x_{mx}\),分析一下可知谁前谁后都一样,看作一个整体,也不会影响其他的数对的排序。
因此只需要按最小值为第一关键字,最大值为第二关键字(当然反一下也可以)排序即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
const int N=1e5+5;
struct node
{
int x,y;
int mi,mx;
friend bool operator < (const node &a,const node &b)
{
if(a.mx==b.mx) return a.mi<b.mi;
else return a.mx<b.mx;
}
}a[N];
int n;
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)
{
int x,y;
cin>>x>>y;
a[i].x=x,a[i].y=y;
a[i].mi=min(x,y),a[i].mx=max(x,y);
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++) cout<<a[i].x<<' '<<a[i].y<<' ';
cout<<'\n';
}
int main ()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int T;
cin>>T;
while(T--) solve();
return 0;
}
D
比较巧妙的思路。
首先肯定是要尽可能地跳到下标更大的位置,然后再拿前面能拿的所有分。但是因为 \(b\) 的存在这不太好直接实现。
考虑建图,跳的过程有两种情况:
- 不跳过,从 \(i\) 到 \(i-1\),没有亏损。
- 跳过,从 \(i\) 跳到 \(b_i\),要亏损 \(a_i\)的分数。
这样的话跑一遍最短路,枚举一下终点 \(i\),\(ans=pre_i-dis_i\)。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
using namespace std;
typedef long long ll;
typedef pair<ll,int> PLI;
const int N=4e5+5,M=N*2;
int n;
ll a[N],b[N];
int e[M],w[M],ne[M],h[N],tot;
void add(int x,int y,int z)
{
e[++tot]=y,w[tot]=z,ne[tot]=h[x],h[x]=tot;
}
bool vis[N];
ll dis[N];
priority_queue<PLI> q;
void dijkstra()
{
for(int i=1;i<=n;i++) vis[i]=0,dis[i]=1e18;
dis[1]=0;
q.push({0,1});
while(q.size())
{
int x=q.top().second;q.pop();
if(vis[x]) continue;
vis[x]=1;
for(int i=h[x];i;i=ne[i])
{
int y=e[i],z=w[i];
if(dis[y]>dis[x]+z)
{
dis[y]=dis[x]+z;
q.push({-dis[y],y});
}
}
}
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i];
for(int i=1;i<=n;i++) h[i]=0;
tot=0;
for(int i=1;i<=n;i++)
{
if(i!=1) add(i,i-1,0);
add(i,b[i],a[i]);
}
dijkstra();
ll ans=0,sum=0;
for(int i=1;i<=n;i++)
{
sum+=a[i];
ans=max(ans,sum-dis[i]);
}
cout<<ans<<'\n';
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
int T;
cin>>T;
while(T--) solve();
return 0;
}