D. Constant Palindrome Sum
题意:给你n长度的数组a[i] n一定为偶数。现在要你进行一个操作:
选择一个下标i 改变其权值 范围为1~k,问最少的操作使得 所有的 a[i]+a[n-i+1] 都相等
做法:考虑每对a[i] 、a[n-i+1] 一个最小值:mi 一个 最大值:mx
0操作可以得到的范围数:mi+mx
1操作可以得到的范围数:【mi+1,mx+k】
2操作可以得到的范围数: 【1,mi】【mx+k,k】 判断一下mx+k与k 的大小即可
那么线段树区间更新单点查询一下即可,也可以差分一下。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=4e5+10;
int n,k;
int a[N];
ll sum[4*N],lazy[4*N];
void qu(int id,int l,int r,int pos,ll &mx)
{
mx+=sum[id];
if(l==r) return ;
int mid=l+r>>1;
if(pos<=mid) qu(id<<1,l,mid,pos,mx);
else qu(id<<1|1,mid+1,r,pos,mx);
}
void up(int id,int l,int r,int ql,int qr,int val)
{
if(ql<=l&&r<=qr) {
sum[id]+=val;
return ;
}
int mid=l+r>>1;
if(ql<=mid) up(id<<1,l,mid,ql,qr,val);
if(qr>mid) up(id<<1|1,mid+1,r,ql,qr,val);
}
void solve()
{
scanf("%d%d",&n,&k);
rep(i,1,n) scanf("%d",&a[i]);
int len=2*k;
rep(i,1,4*len) sum[i]=0;
rep(i,1,n/2) {
int mi=min(a[i],a[n-i+1]);
int mx=max(a[i],a[n-i+1]);
int now=a[i]+a[n-i+1];
int l=mi+1,r=mx+k;
up(1,1,len,l,r,1);
up(1,1,len,now,now,-1);
up(1,1,len,1,l-1,2);
if(r+1<=len) up(1,1,len,r+1,len,2);
}
ll ans=1e18;
rep(i,2,len) {
ll mx=0;qu(1,1,len,i,mx);
ans=min(ans,mx);
}
printf("%lld\n",ans);
}
int main()
{
int _;cin>>_;while(_--)
solve();
}
E. Weights Distributing
题意:给你n个节点m条边的无向图,以及未被分配的m个权值w[i] 现在你要从a到b 再从b到c 求如何分配使得,走过的权值和最小,输出这个权值即可。
做法:求每个点到a、b、c的最短路径(假设权值为1)接着枚举中继点a->v v->b b->v v->c 必然会存在这么一个中继点使得权值和最小,那么重复走的路用最小依次分配即可。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
#define mem(a,x) memset(a,x,sizeof(a))
#define pb push_back
#define pi pair<int, int>
#define mk make_pair
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
struct node
{
int u,w;
bool operator <(const node&o)const{return o.w<w;}
};
const int N=2e5+10;
vector<int>G[N];
int n,m,a,b,c;
ll w[N];
int d1[N],d2[N],d3[N];
const int inf=1e8;
void bfs(int s,int dis[])
{
priority_queue<node>que;
que.push({s,0});
rep(i,1,n) dis[i]=inf;
dis[s]=0;
while(que.size()){
node now=que.top();que.pop();
for(auto v:G[now.u]){
int u1=now.u,v1=v;
if(dis[v]>dis[now.u]+1){
dis[v]=dis[now.u]+1;
que.push({v,dis[v]});
}
}
}
}
void solve()
{
scanf("%d%d%d%d%d",&n,&m,&a,&b,&c);
rep(i,1,n){G[i].clear();}
rep(i,1,m) scanf("%lld",&w[i]);
rep(i,1,m)
{
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
bfs(a,d1);
bfs(b,d2);
bfs(c,d3);
sort(w+1,w+1+m);
rep(i,1,m) w[i]+=w[i-1];
ll ans=1e18;
rep(i,1,n){
int r=d1[i]+d2[i]+d3[i];
if(r>m) continue;
ll mx=w[r]+w[d2[i]];
//printf("r:%d mx:%lld\n",r,mx);
ans=min(ans,mx);
}
printf("%lld\n",ans);
}
int main()
{
int _;cin>>_;while(_--)
solve();
}
/*
7
5 5 1 3 5
1 2 2 2 2
1 2
3 4
2 3
2 5
4 5
*/
F. Restore the Permutation by Sorted Segments
这题题解参考来自:博客
题大:现在有一个长度为 n 的排列 p ,但排列 p 暂时对我们保密,每个样例将会给出 n - 1 个排好序后的子段,换句话说,对于 r ∈ [ 2 , n ] ,存在一个 l 满足 l < r ,题目会给出排列 p 中 [ l , r ] 这段,只不过是排好序后给出,现在让我们还原排列 p
判断所有子段是否合法想了半天,然后博主的的方法特别不错,用set<set<int> >保存输入的子段然后枚举区间 再查询,只要log复杂度
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=2e5+100;
int main()
{
int _;cin>>_;while(_--)
{
vector<set<int> >G;
int n;
scanf("%d",&n);
for(int i=1;i<n;i++)
{
set<int>st;
int k;scanf("%d",&k);
while(k--)
{
int num;
scanf("%d",&num);
st.insert(num);
}
G.push_back(st);
}
for(int st=1;st<=n;st++)//枚举第一个数
{
vector<int>ans;
vector<set<int> >cur=G;
bool flag=true;
for(auto &it:cur) it.erase(st);//删除第一个数
ans.push_back(st);
for(int i=1;i<n;i++)//迭代n-1次,找出剩余n-1个数
{
vector<int>temp;
for(auto &it:cur)
if(it.size()==1)
temp.push_back(*it.begin());
if(temp.size()!=1)//无法找到
{
flag=false;
break;
}
ans.push_back(temp[0]);
for(auto &it:cur) it.erase(temp[0]);
}
set<set<int>>all(G.begin(),G.end());
if(flag)//构造出数列后,判断是否合理
{
for(int l=0;l<n-1;l++)
{
set<int>st;
for(int r=l;r<n;r++)
{
st.insert(ans[r]);
if(all.count(st))all.erase(st);
}
}
}
if(all.empty())//判断合理的话,直接输出答案
{
for(int it:ans)printf("%d ",it);
puts("");
break;
}
}
}
return 0;
}