Solution
A
可以发现,我们可以从小的开始向上推平,例如对于序列 ,我们可以先在 中删掉一个 ,然后在 中删掉一个 ,在 中删掉一个 ……在 中删掉一个 ,以此类推,这样删数毫无疑问是最佳选择。
于是,我们模拟即可,判断最终能否只剩下一个数。同时也可以直接判断,排序后是否相邻两个数之差在 及以内。
B
首先,我们先要想好把 数列和 数列分别改成什么数,显然都是这两个数列的最小值。
于是,考虑对于两个数 ,现在分别把它们改成 需要的最少操作次数。我们需贪心地先尽可能多地一起减 ,再对于一个减 ,即最少操作次数为 。
故答案为 ,其中 与 分别是 序列的最小值。
C
直接枚举显然超时,考虑开桶。 记录下了 出现的次数。
我们首先把桶给建出来,然后枚举对于每一个 ,最多能够参加的组数。此时答案为
注意,当 的时候,它对答案的贡献是 而非 。
时间复杂度 。
D
一道对顶栈的好题(全网貌似就本蒟蒻这么做吧)。
两个栈,第一个栈表示出所有结尾的数为 的子序列的编号,第二个栈记录下所有结尾的数为 的子序列的编号。
如果这个值是 ,那么尝试拿它拼在第二个栈中某个子序列的后面,并让拼后的子序列滚出第二个栈,跳进第一个栈里面。如果第二个栈为空,则新开一个子序列并放在第一个栈里面,答案加一。
如果这个值是 则同理。
此时时间复杂度为 。注意对顶栈可以用数组模拟,所以不要担心不会用 的 啦。
E1
首先,我们思考这样一个问题: 对于一棵带权树,求出根节点到每个叶节点的距离之和。
首先,把边权转为点权,每个点的点权为其与其父亲的边权。然后,假设某个节点的子树中有 个叶子,那么该节点的点权对答案的贡献次数就是 次。算某个节点的子树中的叶节点个数显然可以通过递推预处理得到。若第 个节点的点权为 ,它的子树中叶节点的个数为 ,则这个题目的答案为 。
回到原题,发现这里的 是可变的。可以发现,我们每次都贪心地选择这样一个节点,使得将它进行操作后答案减少得最多,直到答案到达规定范围为止。每次的贪心最优状态(将它进行操作后答案减少得最多)可以用优先队列维护。
注意, 在对 进行操作后, 变小的值应当直接计算为 ,绝对不是 ,本蒟蒻因此 了一次。
E2
可以发现,现在改每条边的代价变得不同了。
首先,我们需要考虑,这题我们要求的是代价的最小值,但边的代价的情况有且仅有两个,即 与 。
对于相同代价的边,我们均按 的方式做,找出对于该类代价的边,得到某种总权值的代价的最小值,显然可以通过 的方法得到。得到了这些之后,我们分别考虑: 通过改代价为 的边,共消耗了 的代价且当前总权值为 ,那么我们需要找到改代价为 的边的总权值 与其代价 ,使得 且 的值最小。由于代价有单调性,我们可以双指针来扫。
例如,对于价值为 的边,权值分别是 , 值分别是 ,则有:
(得到权值为
的情况需要
的代价)
(得到权值为
的情况需要
的代价)
……
另外,代价为 的边的权值为 , 值分别是 ,则有:
……
此时,假设 ,那么,我们直接考虑,用 与 配对, 与 配对……最终用双指针得到答案。
总时间复杂度为 。
Code
#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;
int t,n;
int a[200005],b[200005];
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) cin>>b[i];
int mina=inf,minb=inf,ans=0;
for (int i=1;i<=n;i++) mina=min(mina,a[i]);
for (int i=1;i<=n;i++) minb=min(minb,b[i]);
for (int i=1;i<=n;i++) ans+=max(a[i]-mina,b[i]-minb);
cout<<ans<<endl;
}
return 0;
}
B
#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;
int t,n;
int a[200005],b[200005];
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) cin>>b[i];
int mina=inf,minb=inf,ans=0;
for (int i=1;i<=n;i++) mina=min(mina,a[i]);
for (int i=1;i<=n;i++) minb=min(minb,b[i]);
for (int i=1;i<=n;i++) ans+=max(a[i]-mina,b[i]-minb);
cout<<ans<<endl;
}
return 0;
}
C
#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;
int t,n,x;
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
int a[1005]={0};
for (int i=1;i<=n;i++)
{
cin>>x;
a[x]++;
}
int ans=0;
for (int i=1;i<=100;i++)
{
int now=0;
for (int j=1;j<=i-1;j++)
{
if (j!=i-j) now+=min(a[j],a[i-j]);
else now+=(a[j]/2)*2;
}
ans=max(ans,now);
}
cout<<ans/2<<endl;
}
return 0;
}
D
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n,len0=0,len1=0,len=0,maxv=0;
int a[200005],ans[200005],x[200005],y[200005];
signed main()
{
cin>>t;
while (t--)
{
cin>>n;
len=0,len0=0,len1=0,maxv=0;
for (int i=1;i<=n;i++)
{
char x;
cin>>x;
a[i]=x-'0';
}
for (int i=1;i<=n;i++)
{
int now=a[i]^1;
if (now==0)
{
if (len0>=1)
{
ans[i]=x[len0];
len1++;
y[len1]=x[len0];
len0--;
}
else
{
len++,len1++;
y[len1]=len;
ans[i]=len;
}
}
else
{
if (len1>=1)
{
ans[i]=y[len1];
len0++;
x[len0]=y[len1];
len1--;
}
else
{
len++,len0++;
x[len0]=len;
ans[i]=len;
}
}
maxv=max(maxv,ans[i]);
}
cout<<maxv<<endl;
for (int i=1;i<=n;i++) cout<<ans[i]<<' ';
cout<<endl;
}
return 0;
}
E1
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n,u,v,w,tot,s,ans=0,cnt=0;
int head[500005],l[200005];
struct edge
{
int next;
int to;
int dis;
}e[500005];
struct node
{
int rt;
int num;
}a[200005];
inline void dfs(int now,int fath)
{
for (int i=head[now];i;i=e[i].next)
{
if (e[i].to!=fath)
{
a[e[i].to].rt=e[i].to;
a[e[i].to].num=e[i].dis;
dfs(e[i].to,now);
}
}
}
inline void dfs2(int now,int fath)
{
int flag=1;
for (int i=head[now];i;i=e[i].next)
{
if (e[i].to!=fath)
{
flag=0;
dfs2(e[i].to,now);
l[now]+=l[e[i].to];
}
}
if (flag==1) l[now]=1;
}
inline void add_edge(int u,int v,int w)
{
cnt++;
e[cnt].to=v;
e[cnt].dis=w;
e[cnt].next=head[u];
head[u]=cnt;
}
bool operator < (const node &x,const node &y)
{
int nowx=x.num*l[x.rt]-(x.num/2)*l[x.rt];
int nowy=y.num*l[y.rt]-(y.num/2)*l[y.rt];
return nowx<nowy;
}
signed main()
{
cin>>t;
while (t--)
{
cin>>n>>s;
tot=0,ans=0,cnt=0;
for (int i=1;i<=n;i++) l[i]=0;
for (int i=1;i<=2*n;i++)
{
head[i]=0;
e[i].next=e[i].dis=e[i].to=0;
}
for (int i=1;i<n;i++)
{
cin>>u>>v>>w;
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs(1,0);
dfs2(1,0);
for (int i=1;i<=n;i++) tot+=a[i].num*l[i];
std::priority_queue<node,vector<node> > q;
for (int i=1;i<=n;i++) q.push(a[i]);
while (tot>s)
{
node now=q.top();
q.pop();
tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
now.num/=2;
q.push(now);
ans++;
}
cout<<ans<<endl;
}
return 0;
}
E2
#include <bits/stdc++.h>
#define int long long
using namespace std;
int t,n,u,v,w,w2,tot,s,cnt=0,posl=0,posr=0,nowcost=0,pl,pr,ans,nowtot=0;
int head[500005],l[200005],qwq[200005];
struct edge
{
int next;
int to;
int dis;
int opt;
}e[500005];
struct node
{
int rt;
int num;
}a[2000005];
struct left_graph
{
int num;
int cost;
}le[2000005];
struct right_graph
{
int num;
int cost;
}ri[2000005];
inline void dfs(int now,int fath)
{
for (int i=head[now];i;i=e[i].next)
{
if (e[i].to!=fath)
{
a[e[i].to].rt=e[i].to;
a[e[i].to].num=e[i].dis;
qwq[e[i].to]=e[i].opt;
dfs(e[i].to,now);
}
}
}
inline void dfs2(int now,int fath)
{
int flag=1;
for (int i=head[now];i;i=e[i].next)
{
if (e[i].to!=fath)
{
flag=0;
dfs2(e[i].to,now);
l[now]+=l[e[i].to];
}
}
if (flag==1) l[now]=1;
}
inline void add_edge(int u,int v,int w,int w2)
{
cnt++;
e[cnt].to=v;
e[cnt].dis=w;
e[cnt].next=head[u];
e[cnt].opt=w2;
head[u]=cnt;
}
bool operator < (const node &x,const node &y)
{
int nowx=x.num*l[x.rt]-(x.num/2)*l[x.rt];
int nowy=y.num*l[y.rt]-(y.num/2)*l[y.rt];
return nowx<nowy;
}
signed main()
{
cin>>t;
while (t--)
{
cin>>n>>s;
tot=0,cnt=0,posl=0,posr=0,nowcost=0,ans=1e18+7,nowtot=0;
for (int i=1;i<=n;i++) l[i]=0;
for (int i=1;i<=2*n;i++)
{
head[i]=0;
e[i].next=e[i].dis=e[i].to=0;
}
for (int i=1;i<n;i++)
{
cin>>u>>v>>w>>w2;
add_edge(u,v,w,w2);
add_edge(v,u,w,w2);
}
dfs(1,0);
dfs2(1,0);
std::priority_queue<node,vector<node> > q;
for (int i=1;i<=n;i++) nowtot+=a[i].num*l[i];
if (nowtot<=s)
{
cout<<0<<endl;
continue;
}
for (int i=1;i<=n;i++)
{
if (qwq[i]==1) q.push(a[i]),tot+=a[i].num*l[i];
}
while (tot>0)
{
if (tot<=s)
{
le[++posl].num=tot;
le[posl].cost=nowcost;
}
node now=q.top();
q.pop();
tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
now.num/=2;
q.push(now);
nowcost++;
}
le[++posl].num=tot;
le[posl].cost=nowcost;
while (!q.empty()) q.pop();
nowcost=0;
for (int i=1;i<=n;i++)
{
if (qwq[i]==2) q.push(a[i]),tot+=a[i].num*l[i];
}
while (tot>0)
{
if (tot<=s)
{
ri[++posr].num=tot;
ri[posr].cost=nowcost;
}
node now=q.top();
q.pop();
tot-=now.num*l[now.rt]-(now.num/2)*l[now.rt];
now.num/=2;
q.push(now);
nowcost+=2;
}
ri[++posr].num=tot;
ri[posr].cost=nowcost;
pl=1,pr=posr;
if (posl==0)
{
cout<<ri[1].cost<<endl;
continue;
}
if (posr==0)
{
cout<<le[1].cost<<endl;
continue;
}
for (pl=1;pl<=posl;pl++)
{
while (le[pl].num+ri[pr].num<=s&&pr>1) pr--;
if (le[pl].num+ri[pr].num>s) pr++;
ans=min(ans,le[pl].cost+ri[pr].cost);
}
cout<<ans<<endl;
}
return 0;
}