封面原图 画师礼島れいあ
下午的ICPC网络赛的难受一晚上全都给我打没了 手速拉满再加上秒杀线段树 这场简直了啊 唯一可惜的是最后还是掉出了1000名 一把上蓝应该没啥希望了吧
A - Robin Helps
题意
侠盗罗宾因劫富济贫而闻名于世
罗宾遇到的 n n n 人,从 1 s t 1_{st} 1st 开始,到 n t h n_{th} nth结束。 i i i 第三个人有 a i a_i ai 金子。如果是 a i ≥ k a_i \ge k ai≥k ,罗宾会拿走所有的 a i a_i ai 金子;如果是 a i = 0 a_i=0 ai=0 ,罗宾会给 1 1 1 金子(如果他还有的话)。罗宾开始时有 0 0 0 个金币
求罗宾给了多少人黄金子、
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{int n,k;scanf("%d%d",&n,&k);int now=0;int cnt=0;for(int i=0;i<n;i++){int x;scanf("%d",&x);if(x>=k)now+=x;if(now>0 and x==0){cnt++;now--;}}printf("%d\n",cnt);
}int main()
{int T=1;scanf("%d",&T);while(T--){solve();}return 0;
}
B - Robin Hood and the Major Oak
题意
大橡树每年长出 i i i^i ii 片新叶,它在 1 1 1 年开始长出 1 1 1 片叶子
树叶在树上的寿命为 k k k 年,换句话说, i i i 年长出的叶子会在 i i i 年和 i + k − 1 i+k-1 i+k−1 年之间存在
罗宾认为偶数是幸运数字,请帮助罗宾判断这棵橡树在 n n n 年的叶子数是否为偶数
思路
i i i^i ii的奇偶性一定和 i i i相同 所以直接根据l到r之间的奇数个数判断即可
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll qpow(ll a,ll b,ll mod)
{ll res=1;while(b){if(b&1) res=res*a%mod;a=a*a%mod;b>>=1;}return res;
}void solve()
{ll n,k;scanf("%lld%lld",&n,&k);ll l=n-k+1,r=n;int cnt=r/2-l/2;if(r%2==1)cnt++;if(cnt%2==0){printf("YES\n");}else{printf("NO\n");}
}int main()
{int T=1;scanf("%d",&T);while(T--){solve();}return 0;
}
C - Robin Hood in Town
题意
给一个数组中最大的数加上一个最小的x使得这个数组中严格大于一半的数都严格小于数组新的平均数的一半
思路
先找到这个平均数最小的值是多少 然后二分查找一个合适的k 分母记得乘过去 否则会有精度问题
二分记得开到1e18
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;void solve()
{ll n;scanf("%lld",&n);ll a[n];ll sum=0;for(int i=0;i<n;i++){scanf("%lld",&a[i]);sum+=a[i];}if(n<=2){printf("-1\n");return ;}sort(a,a+n);ll avg=a[n/2];ll l=0,r=1e18;while(l<r){ll mid=(l+r)/2;ll now=sum+mid;if(now>avg*2*n)r=mid;elsel=mid+1;}printf("%lld\n",l);
}int main()
{int T=1;scanf("%d",&T);while(T--){solve();}return 0;
}
D - Robert Hood and Mrs Hood
题意
给你k个区间,你要选取一个长度为d的区间,分别输出与这个区间相交区间最多和最少得情况的区间起点
思路
线段树维护每一个位置开始会覆盖到多少个区间,每次都是 l − d + 1 l-d+1 l−d+1到 r r r这个区间一起+1
线段树用的板子在这里
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
#define MAXN 1000001
using namespace std;
ll n,m,a[MAXN],ans[MAXN<<2],tag[MAXN<<2];
inline ll ls(ll x)
{return x<<1;
}
inline ll rs(ll x)
{return x<<1|1;
}
inline void push_up(ll p)
{ans[p]=ans[ls(p)]+ans[rs(p)];
}
void build(ll p,ll l,ll r)
{tag[p]=0;if(l==r){ans[p]=a[l];return ;}ll mid=(l+r)>>1;build(ls(p),l,mid);build(rs(p),mid+1,r);push_up(p);
}
inline void f(ll p,ll l,ll r,ll k)
{tag[p]=tag[p]+k;ans[p]=ans[p]+k*(r-l+1);
}
inline void push_down(ll p,ll l,ll r)
{ll mid=(l+r)>>1;f(ls(p),l,mid,tag[p]);f(rs(p),mid+1,r,tag[p]);tag[p]=0;
}
inline void update(ll nl,ll nr,ll l,ll r,ll p,ll k)
//nl,nr为要修改的区间,l,r为当前节点区间,p为当前节点编号,k为要加上的值
{if(nl<=l&&r<=nr){ans[p]+=k*(r-l+1);tag[p]+=k;return ;}push_down(p,l,r);ll mid=(l+r)>>1;if(nl<=mid)update(nl,nr,l,mid,ls(p),k);if(nr>mid) update(nl,nr,mid+1,r,rs(p),k);push_up(p);
}
ll query(ll q_x,ll q_y,ll l,ll r,ll p)
{ll res=0;if(q_x<=l&&r<=q_y)return ans[p];ll mid=(l+r)>>1;push_down(p,l,r);if(q_x<=mid)res+=query(q_x,q_y,l,mid,ls(p));if(q_y>mid) res+=query(q_x,q_y,mid+1,r,rs(p));return res;
}void solve()
{int n,d,k;scanf("%d%d%d",&n,&d,&k);build(1,1,n);while(k--){ll l,r;scanf("%lld%lld",&l,&r);update(max(1ll,l-d+1),r,1,n,1,1);//从l-d+1到r都要加1}//找值最小的位置和最大的位置ll minn=1,maxx=1;ll nowmin=query(1,1,1,n,1);ll nowmax=query(1,1,1,n,1);for(int i=1;i<=n-d+1;i++){ll now=query(i,i,1,n,1);if(now<nowmin){nowmin=now;minn=i;}if(now>nowmax){nowmax=now;maxx=i;}}printf("%lld %lld\n",maxx,minn);
}int main()
{int T=1;scanf("%d",&T);while(T--){solve();}return 0;
}
E - Rendez-vous de Marian et Robin
题意
建了一个图,1和n点各有一个人相向而行,每条边花费的时间等于边权,但是有h个点有马,走到有马的点之后的每条边花费的时间都会变成边权的一半,问两人在任意位置相遇花费的最短时间
思路
dijkstra堆优化维护左端和右端到每个点的时间,有马和无马跑两次,然后遍历每个点算答案
代码
F - Sheriff’s Defense
题意
n-1条边的一个无向图,每次可以使与一个节点的所有节点权值全部减c来使这个节点的最终权值可以加入答案的计算,求最大的答案
思路
每一个点加固与否,一个很明显的dp,跑一遍就行了
记得开long long
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int N=2e5+10,M=N*2;
int n,m;
int w[N],dp[N][2];
vector<int> G[N];void dfs(int u,int fa)
{dp[u][0]=0;dp[u][1]=w[u];for(auto v:G[u]){if(v==fa) continue;dfs(v,u);dp[u][0]+=max(dp[v][0],dp[v][1]);dp[u][1]+=max(dp[v][0],dp[v][1]-m*2);}
}void solve()
{scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++){scanf("%lld",&w[i]);G[i].clear();}for(int i=1;i<=n-1;i++){int u,v;scanf("%lld%lld",&u,&v);G[u].push_back(v);G[v].push_back(u);}dfs(1,-1);printf("%lld\n",max(dp[1][0],dp[1][1]));
}signed main()
{int T=1;scanf("%d",&T);while(T--){solve();}return 0;
}