可以发现,我们可以从小的开始向上推平,例如对于序列 1 1 2 3 3 4 1\ 1\ 2\ 3\ 3\ 4 1 1 2 3 3 4,我们可以先在 1 , 1 1,1 1,1中删掉一个 1 1 1,然后在 1 , 2 1,2 1,2中删掉一个 1 1 1,在 2 , 3 2,3 2,3中删掉一个 2 2 2……在 3 , 4 3,4 3,4中删掉一个 3 3 3,以此类推,这样删数毫无疑问是最佳选择。
于是,我们模拟即可,判断最终能否只剩下一个数。同时也可以直接判断,排序后是否相邻两个数之差在 1 1 1及以内。
首先,我们先要想好把 A A A数列和 B B B数列分别改成什么数,显然都是这两个数列的最小值。
于是,考虑对于两个数 x , y x,y x,y,现在分别把它们改成 a , b a,b a,b需要的最少操作次数。我们需贪心地先尽可能多地一起减 1 1 1,再对于一个减 1 1 1,即最少操作次数为 m a x ( x − a , y − b ) max(x-a,y-b) max(x−a,y−b)。
故答案为 ∑ i = 1 n m a x ( a i − x , b i − y ) \sum_{i=1}^n max(a_i-x,b_i-y) ∑i=1nmax(ai−x,bi−y),其中 x x x与 y y y分别是 A , B A,B A,B序列的最小值。
直接枚举显然超时,考虑开桶。 v i v_i vi记录下了 i i i出现的次数。
我们首先把桶给建出来,然后枚举对于每一个 s s s,最多能够参加的组数。此时答案为
∑ i = 1 s − 1 m i n ( v i , v s − i ) \sum_{i=1}^{s-1} min(v_i,v_{s-i}) ∑i=1s−1min(vi,vs−i)
注意,当 i = s − i i=s-i i=s−i的时候,它对答案的贡献是 ⌊ v i 2 ⌋ \lfloor \frac {v_i} 2 \rfloor ⌊2vi⌋而非 m i n ( v i , v s i ) min(v_i,v_{s_i}) min(vi,vsi)。
时间复杂度 O ( t n 2 ) O(tn^2) O(tn2)。
一道对顶栈的好题(全网貌似就本蒟蒻这么做吧)。
两个栈,第一个栈表示出所有结尾的数为 0 0 0的子序列的编号,第二个栈记录下所有结尾的数为 1 1 1的子序列的编号。
如果这个值是 0 0 0,那么尝试拿它拼在第二个栈中某个子序列的后面,并让拼后的子序列滚出第二个栈,跳进第一个栈里面。如果第二个栈为空,则新开一个子序列并放在第一个栈里面,答案加一。
如果这个值是 1 1 1则同理。
此时时间复杂度为 O ( n ) O(n) O(n)。注意对顶栈可以用数组模拟,所以不要担心不会用 S T L STL STL的 s t a c k stack stack啦。
首先,我们思考这样一个问题: 对于一棵带权树,求出根节点到每个叶节点的距离之和。
首先,把边权转为点权,每个点的点权为其与其父亲的边权。然后,假设某个节点的子树中有 k k k个叶子,那么该节点的点权对答案的贡献次数就是 k k k次。算某个节点的子树中的叶节点个数显然可以通过递推预处理得到。若第 i i i个节点的点权为 a i a_i ai,它的子树中叶节点的个数为 l i l_i li,则这个题目的答案为 ∑ i = 1 n a i × l i \sum_{i=1}^n a_i×l_i ∑i=1nai×li。
回到原题,发现这里的 a i a_i ai是可变的。可以发现,我们每次都贪心地选择这样一个节点,使得将它进行操作后答案减少得最多,直到答案到达规定范围为止。每次的贪心最优状态(将它进行操作后答案减少得最多)可以用优先队列维护。
注意, a i × l i a_i×l_i ai×li在对 i i i进行操作后, a i × l i a_i×l_i ai×li变小的值应当直接计算为 a i × l i − ( ⌊ a i 2 ⌋ ) l i a_i×l_i-(\lfloor \frac {a_i} 2\rfloor)l_i ai×li−(⌊2ai⌋)li,绝对不是 ⌊ a i × l i 2 ⌋ \lfloor \frac {a_i×l_i} 2 \rfloor ⌊2ai×li⌋,本蒟蒻因此 W A WA WA了一次。
可以发现,现在改每条边的代价变得不同了。
首先,我们需要考虑,这题我们要求的是代价的最小值,但边的代价的情况有且仅有两个,即 1 1 1与 2 2 2。
对于相同代价的边,我们均按 E 1 E1 E1的方式做,找出对于该类代价的边,得到某种总权值的代价的最小值,显然可以通过 E 1 E1 E1的方法得到。得到了这些之后,我们分别考虑: 通过改代价为 1 1 1的边,共消耗了 k k k的代价且当前总权值为 w w w,那么我们需要找到改代价为 2 2 2的边的总权值 w 2 w_2 w2与其代价 k 2 k_2 k2,使得 w 2 + w ≤ S w_2+w≤S w2+w≤S且 k 2 + k k_2+k k2+k的值最小。由于代价有单调性,我们可以双指针来扫。
例如,对于价值为 1 1 1的边,权值分别是 10 , 12 , 15 10,12,15 10,12,15, l l l值分别是 1 , 1 , 1 1,1,1 1,1,1,则有:
37 : 0 37: 0 37:0(得到权值为 37 37 37的情况需要 0 0 0的代价)
29 : 1 29: 1 29:1(得到权值为 29 29 29的情况需要 1 1 1的代价)
23 : 2 23: 2 23:2
18 : 3 18:3 18:3
14 : 4 14:4 14:4
11 : 5 11:5 11:5
8 : 6 8:6 8:6
……
另外,代价为 2 2 2的边的权值为 3 , 4 3,4 3,4, l l l值分别是 1 , 1 1,1 1,1,则有:
7 : 0 7:0 7:0
5 : 1 5:1 5:1
3 : 2 3:2 3:2
2 : 3 2:3 2:3
……
此时,假设 s = 25 s=25 s=25,那么,我们直接考虑,用 23 23 23与 2 2 2配对, 18 18 18与 7 7 7配对……最终用双指针得到答案。
总时间复杂度为 O ( n ∑ i = 1 n l o g 2 a i n ) O(n \sum_{i=1}^n log_2 a_in) O(n∑i=1nlog2ain)。
#include
#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;
}
#include
#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;
}
#include
#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;
}
#include
#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;
}
#include
#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;
}
#include
#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;
}