Atcoder beginner contest 395(A,B,C,补DEF)

atcoder beginner contest 395

赛时ABC,赛后DEF(希望cf灰名有朝一日能稳定4-5题)

A :直接模拟

B:同上

C:一个map存出现次数,再用一个数组存一个数上一次出现的次数,ans = min(ans, i - lastnumber[a[i]]+1);

```#include<bits/stdc++.h>
#define N 1000005
#define mod 998244353
using namespace std;
typedef long long ll;
int b[N];
void solve()
{
    int n;
    cin>>n;
    vector<int>a(n+1);
    map<int,int>mp;
    int ans = INT_MAX;
    for(int i = 1;i <= n;i++)
    {
        cin>>a[i];
        mp[a[i]]++;
        if(mp[a[i]] >=2)
        {
            //ans = INT_MAX;
            ans = min(i-b[a[i]]+1,ans);
        }
        b[a[i]] = i;
    }
    if(ans !=INT_MAX)   cout<<ans;
    else    cout<<-1;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T = 1;
    while(T--)
      solve();
    return 0;
}

D:多个数组维护:

n个鸽子和鸟巢,初始鸽子i在鸟巢i

1操作把鸽子a放进鸟巢b
2操作把鸟巢a和鸟巢b鸽子交换
3操作查询鸽子a所在鸟巢编号

idea:乍一看似乎是一个冰茶机问题,但仅仅并查集处理不太行,需要维护一点信息,因为操作A如果是对子树根节点进行处理,

则它的叶子结点会被破坏image

如图,如果要把黄色箭头指向的鸽子放到另一个笼子里,若是简单的并查集吗,则它的叶子节点会被破坏

因此可以这样考虑:

1.一个数组f维护鸽子i在哪个笼子

2.一个数组p维护笼子i的编号

3.一个数组r维护编号为i的笼子的位置、

则对于操作1:f[a] = r[b]

对于操作2:p[f[a]] = b,p[f[b]] = a,swap(r[a],r[b]);**

因为这里要把a中所有鸽子放到b笼子里,相当于把a所在的笼子的门牌号换为b,b同理,同时注意修改r数组

对于操作3:则只需输出p[f[a]]即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+5;
int f[N],p[N],r[N];
void init()
{
	for(int i = 1;i <= N-1;i++)
	{
		f[i] = i;//鸽子编号
		p[i] = i;//鸽子所在笼子的门牌号
		r[i] = i;//门牌号为i对应的鸽子笼编号
	}
}
void solve()
{
	int n,q;
	cin>>n>>q;
	init();
	while(q--)
	{
		int op;
		cin>>op;
		if(op==1)
		{
			int a,b;
			cin>>a>>b;
			f[a] = r[b];
		}
		if(op==2)
		{
			int a,b;
			cin>>a>>b;
			p[r[a]] = b;
			p[r[b]] = a;
			swap(r[a],r[b]);
		}
		if(op==3)
		{
			int x;
			cin>>x;
			cout<<p[f[x]]<<"\n";
		}
	}
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	int T = 1;
	//cin>>T;
	while(T--)
	{
		solve();
	}
}

E:分层图+最短路

题意描述:给定一个X,对一个N个顶点M条边的有向图,从1->N的最小代价,每条边的边权为1,同时可以进行反转操作,花费X的代价将u->v的边反置为v->u,边权也为1

idea:考虑两层的分层图,对于每个节点自身,边权设为X即可,使用优先队列优化后即为dij模板

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e5+5;
vector<pair<int,int>>G[N*2];
priority_queue<pair<long long ,int>,vector<pair<long long ,int>>,greater<pair<long long ,int>>>q;
ll dis[N*2];
bool used[N*2];
int n,m,x;
void addedge(int u,int v,int w)
{
	G[u].emplace_back(v,w);
}
void solve()
{
	cin>>n>>m>>x;
	for(int i = 1;i <= m;i++)
	{
		int u,v;
		cin>>u>>v;
		addedge(u,v,1);
		addedge(v+n,u+n,1);
	}
	for(int i = 1;i <= n;i++)
	{
		addedge(i,i+n,x);
		addedge(n+i,i,x);
	}
	for(int i = 1;i <= 2*n;i++)	dis[i] = 1e18;
	dis[1]=0;
	q.push({0,1});
	while(!q.empty())
	{
		auto [u,v] = q.top();
		q.pop();
		if(used[v])	continue;
		used[v] = 1;
		for(auto [to,w]: G[v])
		{
			if(dis[to] > dis[v] + w)
			{
				dis[to] = dis[v]+w;
				q.push({dis[to],to});
			}
		}	
	}
	cout<<min(dis[n],dis[2*n]);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	int T = 1;
	//cin>>T;
	while(T--)
	{
		solve();
	}
}

F:二分答案(差分约束)

题意描述:长度为n的序列分别为u[i]与d[i],给定一个X;对于每个正数,可以花费1的代价使其减小1,能否找到最小花费满足下列条件

1:u[i] + d[i] = H;(固定的数)

2.对于每个1 < i <= n,|u[i]-u[i-1]| <=X

idea:思考,只要确定一个H,即可算出最后的答案,同时答案可以转化为\sum_{i=1}^{n} (u[i]+d[i]) - H

要使得花费最小,则H应尽可能大,那么这里考虑H的单调性,对于H,如果H成立,则H-1也一定成立

下面是证明:

对于正数序列,如果修改后的序列为

u'[1],u'[2]..u;[n]

d'[1],d'[2],d'[n]

如果把H修改为H-1,则考虑把每个u'[i]变为u[i]-1,那么对于相邻的数,他们的差不变,既然H满足\abs{u[i]-u[i-1]} <= X,则显然H-1也满足#证毕

则现在考虑使用二分答案,来找到一个最大的H,同时使得序列满足条件

那么现在考虑两个条件,对于1,2,显然1更容易满足

现在假设修改后的u'[i] = t,则d'[i] = H-t;

对于2,假设修改后满足条件的数为u'[i],那么显然有u'[i] ≤ u[i],d'[i] ≤ d[i];

则有t ≤ u[i],H-t ≤ d[i] ---> max(0, H-d[i] )≤ t ≤ u[i]

那么对于修改后的每个u'[i],都有一个对应的区间使得 L[i] ≤ t ≤ R[i]

其中的L[i] 应该同时满足两个条件,因此,L[i] = max(H-d[i] , lastL - X )

lastL表示上一个u'[i]的取值,要满足abs(u'[i-1] - t) ≤ X ,则 u'[i-1] - X ≤ t ≤ u'[i-1] + X

对于R[i]也应该同时满足两个条件,因此,R[i] = min(u[i],lastR + X)

#include<bits/stdc++.h>
#define N 1005
#define mod 998244353
using namespace std;
typedef long long ll;

void solve()
{
    int n,x;
    cin>>n>>x;
    ll l = 0,r = 2e9;
    ll sum = 0;
    vector<int>u(n+1),d(n+1);
    for(int i = 1;i <= n;i++)
    {
        cin>>u[i]>>d[i];
        sum+=u[i] + d[i];
        r = min<ll>(r,u[i]+d[i]);
    }
    ll ans = -1;
    auto check = [&](ll H)
    {
        ll lstL = max(0ll,H-d[1]),lstR = u[1];
        for(int i =2 ;i <= n;i++)
        {
            lstL = max<ll>(max<ll>(lstL-x,H-d[i]),0);
            lstR = min<ll>(lstR + x,u[i]);
            if(lstL > lstR) return false;
        }
        return true;
    };
    
    while(l <= r)
    {
        ll mid = (l+r)>>1;
        if(check(mid))  ans = mid,l = mid+1;
        else    r = mid - 1;
    }
    cout<<sum - (ans*n)<<"\n";
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T = 1;
    while(T--)
      solve();
    return 0;
}
posted @ 2025-03-06 09:38  graspppp  阅读(23)  评论(0编辑  收藏  举报