前言
感觉还是科技树不够,E没有缩点的思维拿堆硬搞调了半天,F压根不知道这个trick......
一、A - Feet
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18ll
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int a,b;
cin>>a>>b;
cout<<12*a+b<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
没啥好说的,直接计算即可。
这应该是最简单的A了()
二、B - Tombola
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18ll
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int h,w,n;
cin>>h>>w>>n;
vector<vector<int>>g(h+1,vector<int>(w+1));
for(int i=1;i<=h;i++)
{
for(int j=1;j<=w;j++)
{
cin>>g[i][j];
}
}
set<int>st;
for(int i=1,x;i<=n;i++)
{
cin>>x;
st.insert(x);
}
int ans=0;
for(int i=1;i<=h;i++)
{
int sum=0;
for(int j=1;j<=w;j++)
{
if(st.find(g[i][j])!=st.end())
{
sum++;
}
}
ans=max(ans,sum);
}
cout<<ans<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
因为数据范围不是很大,所以可以直接枚举。
那么就是把b[i]中的每个数存set,然后考察每一行,在set中就增加,最后求最大值即可。
三、C - Reindeer and Sleigh 2
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18ll
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n;
cin>>n;
vector<vector<ll>>a(n+1,vector<ll>(2));
ll sum=0;
for(int i=1;i<=n;i++)
{
//w p
cin>>a[i][0]>>a[i][1];
sum+=a[i][0];
}
sort(a.begin()+1,a.end(),[&](vector<ll>&x,vector<ll>&y)
{
return x[0]+x[1]>y[0]+y[1];
});
vector<ll>suf(n+2);
for(int i=n;i>=1;i--)
{
suf[i]=suf[i+1]+a[i][0];
}
ll pre=0;
for(int i=1;i<=n;i++)
{
pre+=a[i][1];
if(pre>=suf[i+1])
{
cout<<n-i<<endl;
return ;
}
}
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这个贪心没猜到直接给我硬控了一会儿......
多举几个例子观察可以发现,选出来坐雪橇的驯鹿肯定既想让其重量小,也想让其力量小,所以可以考虑根据重量+力量从大到小排序,然后维护一下重量的后缀和。那么在从左往右扫的过程中,当找到第一个前缀力量大于等于后缀重量的位置,即最小拉车的个数,就可以输出了。
四、D - Sum of Differences
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18ll
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
const int MOD=998244353;
int bs(int v,vector<ll>&a)
{
int l=1;
int r=a.size()-1;
int m;
int ans=0;
while(l<=r)
{
m=l+r>>1;
if(a[m]<=v)
{
ans=m;
l=m+1;
}
else
{
r=m-1;
}
}
return ans;
}
void solve()
{
int n,m;
cin>>n>>m;
vector<ll>a(n+1);
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
vector<ll>b(m+1);
for(int i=1;i<=m;i++)
{
cin>>b[i];
}
sort(b.begin()+1,b.end());
vector<ll>pre(m+1);
for(int i=1;i<=m;i++)
{
pre[i]=(pre[i-1]+b[i])%MOD;
}
ll ans=0;
for(int i=1;i<=n;i++)
{
int pos=bs(a[i],b);
ans=(ans+( (pos*a[i]%MOD-pre[pos]+MOD)%MOD+((pre[m]-pre[pos]+MOD)%MOD-(m-pos)*a[i]%MOD+MOD)%MOD)%MOD )%MOD;
}
cout<<ans<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
牛魔前缀和没取模还给我WA了一发......
这题确实一眼二分吧()考虑对b数组排序后,构建前缀和数组。之后扫一遍a数组,每次去b数组里二分找小于等于a[i]的最右位置。由于左侧都是小于等于a[i]的,右侧都是大于等于a[i]的,所以就可以把绝对值去掉,直接计算对答案的贡献。
五、E - Sort Arrays
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define INF 1e9
#define INFLL 1e18ll
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
void solve()
{
int n;
cin>>n;
vector<int>x(n+1);
vector<int>y(n+1);
for(int i=1;i<=n;i++)
{
cin>>x[i]>>y[i];
}
vector<vector<pii>>g(n+1);
for(int i=1;i<=n;i++)
{
g[x[i]].push_back({y[i],i});
}
for(int i=1;i<=n;i++)
{
sort(g[i].begin(),g[i].end());
}
vector<int>ans(n+1);
int fill=1;
auto dfs=[&](auto &&self,vector<int>cur)->void
{
priority_queue<pii,vector<pii>,greater<pii>>heap;
for(auto u:cur)
{
for(auto [w,v]:g[u])
{
heap.push({w,v});
}
}
while(!heap.empty())
{
auto cur=heap.top().first;
vector<int>nx;
while(!heap.empty()&&heap.top().first==cur)
{
auto [w,v]=heap.top();
heap.pop();
nx.push_back(v);
ans[fill++]=v;
}
self(self,nx);
}
};
vector<int>cur={0};
dfs(dfs,cur);
for(int i=1;i<=n;i++)
{
cout<<ans[i]<<" ";
}
cout<<endl;
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
这是怎么做到又像dfs又像bfs的......
首先考虑对于每个操作,建立一条x[i]到i边权为y[i]的边,那么结果肯定构成一棵树,可以看作一棵字典树。之后,对于一条链上的节点,由于前缀相同,长度递增,所以肯定是先输出层数更低的节点。而对于相同长度的节点,肯定是先输出边权更小的节点。
所以可以先对每个g[i]排序,即保证每个节点的孩子节点满足从小到大。之后,考虑带着一张表去dfs,这张表记录上一层处理过的点。所以每次可以考虑用小根堆去维护表中所有点的孩子节点,那么就是每次考虑边权相同的一批点。因为这些点长度最小,所以就先输出这些点,然后带着这些点去调递归。
其实可以直接用map的,这实现太史了......
六、F - Manhattan Christmas Tree 2
cpp
#include <bits/stdc++.h>
using namespace std;
/* /\_/\
* (= ._.)
* / > \>
*/
/*
*想好再写
*注意审题 注意特判
*不要红温 不要急躁 耐心一点
*WA了不要立马觉得是思路不对 先耐心找反例
*/
#define dbg(x) cout<<#x<<endl;cout<<x<<endl;
#define vdbg(a) cout<<#a<<endl;for(auto x:a)cout<<x<<" ";cout<<endl;
#define YES cout<<"YES"<<endl;return ;
#define Yes cout<<"Yes"<<endl;return ;
#define NO cout<<"NO"<<endl;return ;
#define No cout<<"No"<<endl;return ;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
const int INF=1e9;
const ll INFLL=1e18;
const int dx[]={-1,1,0,0};
const int dy[]={0,0,-1,1};
const int ddx[]={-2,-1,1,2,2,1,-1,-2};
const int ddy[]={1,2,2,1,-1,-2,-2,-1};
const int MAXN=2e5+5;
vector<array<ll,2>>a(MAXN);
vector<ll>LMIN(MAXN<<2);
vector<ll>RMIN(MAXN<<2);
vector<ll>LMAX(MAXN<<2);
vector<ll>RMAX(MAXN<<2);
void up(int i)
{
int l=i<<1,r=i<<1|1;
LMIN[i]=min(LMIN[l],LMIN[r]);
LMAX[i]=max(LMAX[l],LMAX[r]);
RMIN[i]=min(RMIN[l],RMIN[r]);
RMAX[i]=max(RMAX[l],RMAX[r]);
}
void build(int l,int r,int i)
{
if(l==r)
{
LMIN[i]=LMAX[i]=a[l][0]+a[l][1];
RMIN[i]=RMAX[i]=a[l][0]-a[l][1];
}
else
{
int m=l+r>>1;
build(l,m,i<<1);
build(m+1,r,i<<1|1);
up(i);
}
}
void change(int jobi,int jobx,int joby,int l,int r,int i)
{
if(l==r)
{
LMIN[i]=LMAX[i]=jobx+joby;
RMIN[i]=RMAX[i]=jobx-joby;
}
else
{
int m=l+r>>1;
if(jobi<=m)
{
change(jobi,jobx,joby,l,m,i<<1);
}
else
{
change(jobi,jobx,joby,m+1,r,i<<1|1);
}
up(i);
}
}
array<ll,4> query(int jobl,int jobr,int l,int r,int i)
{
if(jobl<=l&&r<=jobr)
{
return {LMIN[i],RMIN[i],LMAX[i],RMAX[i]};
}
int m=l+r>>1;
array<ll,4>left={INFLL,INFLL,-INFLL,-INFLL};
if(jobl<=m)
{
left=query(jobl,jobr,l,m,i<<1);
}
array<ll,4>right={INFLL,INFLL,-INFLL,-INFLL};
if(m+1<=jobr)
{
right=query(jobl,jobr,m+1,r,i<<1|1);
}
return {min(left[0],right[0]),min(left[1],right[1]),max(left[2],right[2]),max(left[3],right[3])};
}
void solve()
{
int n,q;
cin>>n>>q;
for(int i=1;i<=n;i++)
{
cin>>a[i][0]>>a[i][1];
}
build(1,n,1);
int op,i,x,y,l,r;
while(q--)
{
cin>>op;
if(op==1)
{
cin>>i>>x>>y;
change(i,x,y,1,n,1);
}
else
{
cin>>l>>r>>x>>y;
auto res=query(l,r,1,n,1);
ll xx=x+y;
ll yy=x-y;
cout<<max({
xx-res[0],yy-res[1],res[2]-xx,res[3]-yy
})<<endl;
}
}
}
void init()
{
}
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
init();
while(t--)
{
solve();
}
return 0;
}
直接维护曼哈顿距离的话,单点修改操作其实不太好实现,那么就需要考虑进行转化。
对于曼哈顿距离,常见的转化就是将其转化为切比雪夫距离。首先,两点(a,b)和(x,y)之间的切比雪夫距离就是max(abs(a-x),abs(b-y))。直接说结论,对于点(x,y),将其转化为点(x+y,x-y)后,此时的切比雪夫距离就是原来点的曼哈顿距离。
那么有了这个trick,将所有点转化以后,对于范围查询操作,只需要维护[l,r]范围内横纵坐标的最大最小值,看给定的点和哪个值的差值最大即可。那么这个值就是当前坐标下切比雪夫距离的最大值,也就是原坐标下曼哈顿距离的最大值。
总结
感觉现在需要点科技树了......