2022-2023 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2022)(A~H)组队训练题解

比赛链接:https://codeforces.com/gym/104030
赛后补:E和F

A.Ace Arbiter

思路:仔细一看数据范围最大就是11+10,那就2的22次方得了,显然数量级在1e6,所以直接暴力dfs即可,记得前面给的记录去重下

#include<bits/stdc++.h>
#define endl "\n"
#include<functional>

using namespace std;
typedef long long ll;

const int INF=0x3f3f3f3f;
const int N=2e5+5;


void fio(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}
pair<ll,ll>f[450];
ll cnt=0;
ll k[450];
void solve()
{
    ll n;
	scanf("%lld",&n);
	for(ll i=1;i<=n;i++)
	{
		ll l,r;
		scanf("%lld-%lld",&l,&r);
		if(cnt==0)f[++cnt].first=l,f[cnt].second=r,k[cnt]=cnt;
		else if(f[cnt].first==l&&f[cnt].second==r)k[cnt]=i;
		else f[++cnt].first=l,f[cnt].second=r,k[cnt]=i;
	}
	ll ans=0;
	function<void(ll,ll,ll,ll)>dfs=[&](ll s,ll js,ll x,ll y)
	{
		if(s<=cnt&&(x==f[s].first&&y==f[s].second))
		{
			ans=max(ans,s);
			s++;
		}
		if(s>cnt)
		return;
		if(x==11||y==11)return ;
		if(js==1)
		{
			dfs(s,js+1,y+1,x);
			dfs(s,js+1,y,x+1);
		}
		else if((js-1)%4==1)
		{
			dfs(s,js+1,x+1,y);
			dfs(s,js+1,x,y+1);
		}
		else if((js-1)%4==2)
		{
			dfs(s,js+1,y,x+1);
			dfs(s,js+1,y+1,x);
		}
		else if((js-1)%4==3)
		{
			dfs(s,js+1,x+1,y);
		    dfs(s,js+1,x,y+1);
		}
		else 
		{
			dfs(s,js+1,y,x+1);
			dfs(s,js+1,y+1,x);
		}
		return ;
	};
	dfs(1,1,0,0);
	if(ans!=cnt)
	{	
		printf("error %lld\n",k[ans]+1);
	}
	else printf("ok\n");
}

signed main()
{
//	fio();
	ll t;
	//cin >> t;
	t=1;
	while(t--){
		solve();
	}
	return 0;
}

 

B.Berry Battle

思路:自己手画了一下,树的直径小于等于3必定无解,否则先按照树的直径如1 2 3 4 5 6...,先1 3 4 2,然后5 6...,把树的直径的坐标按我左边这样排即可,然后在另一个树的端点bfs最近没有被用过的点即可,这种显然可保证蚂蚁永远不会同时到同一个点

#include<bits/stdc++.h>
#define endl "\n"
#include<functional>

using namespace std;
typedef long long ll;

const int INF=0x3f3f3f3f;
const int N=2e5+5;


void fio(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}
ll ef[350000];
bool vis[350000];
bool vi[350000];
vector<ll> g[350000];
void solve()
{
    ll n;
    cin>>n;
    for(ll i=1;i<n;i++)
    {
        ll l,r;
        cin>>l>>r;
        g[l].push_back(r);
        g[r].push_back(l);
    }  
   // cout<<156<<endl;
    ll f=0,id=0;
    function<void(ll,ll,ll)>dfs=[&](ll x,ll fa,ll d)
    {
        if(f<d)f=d,id=x;
        for(auto j:g[x])
        {
            if(j==fa)continue;
            dfs(j,x,d+1);
        }
    };
    dfs(1,0,1);   
    ll id1=0;f=0;
    function<void(ll,ll,ll)>df=[&](ll x,ll fa,ll d)
    {
        if(f<d)f=d,id1=x;
        for(auto j:g[x])
        {
            if(j==fa)continue;
            df(j,x,d+1);
        }
    };
    df(id,0,1);
    if(f<=3)
    cout<<"NO"<<endl;
    else
    { 
    vector<ll>ans,op;
    ll pd=0;
    function<void(ll,ll)>l=[&](ll x,ll fa)
    { 
        op.push_back(x);
        if(x==id1)
        {
            pd=1;
            ans=op;
            return ;
        }
        if(pd)return;
        for(auto j:g[x])
        {
            if(j==fa)continue;
            l(j,x);
            if(pd)
            return;
        }
        op.pop_back();
    };
    l(id,0);
    ll cnt=0;
    ef[++cnt]=ans[0],vis[ans[0]]=1;
    ef[++cnt]=ans[2],vis[ans[2]]=1;
    ef[++cnt]=ans[3],vis[ans[3]]=1;
    ef[++cnt]=ans[1],vis[ans[1]]=1;
    for(auto j:ans)
    {
        if(vis[j])continue;
        ef[++cnt]=j,vis[j]=1;
    }
    function<void(ll)>bfs=[&](ll x)
    {
        queue<ll>f;
        f.push(x);
        while(!f.empty())
        {
            ll x=f.front();
            f.pop();
            if(vi[x])continue;
            vi[x]=1;
            if(vis[x]==0)
            ef[++cnt]=x;
            vis[x]=1;
            for(auto j:g[x])
            {
                if(vi[j])continue;
                f.push(j);
            }
        }
    };
    bfs(id1);
    cout<<"YES"<<endl;
    for(ll i=1;i<=cnt;i++)
    cout<<ef[i]<<" ";
    cout<<endl;
    }
}

signed main()
{
	fio();
	ll t;
	//cin >> t;
	t=1;
	while(t--){
		solve();
	}
	return 0;
}

C.Coffee Cup Combo

思路:签到题,不多说了

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;
typedef long long ll;

const int INF=0x3f3f3f3f;
const int N=2e5+5;

ll t,n,m;

void fio(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}

void solve(){
	
	string str;
	cin >> n >> str;
	ll cnt=0;
	ll ans=0;
	for(auto i:str){
		if(i=='0' && cnt!=0){
			cnt--;
			ans++;
		}
		else if(i=='1'){
			ans++;
			cnt=2;
		}
	}
	cout << ans << endl;
}


signed main()
{
	fio();
	//cin >> t;
	t=1;
	while(t--){
		solve();
	}
	return 0;
}

D.Disc District

思路:显然欧几里得距离大于r的一个整数坐标点,那么(r,1)即可

#include<bits/stdc++.h>
#define endl '\n'

using namespace std;
typedef long long ll;

const int INF=0x3f3f3f3f;
const int N=2e5+5;

ll t,n,m;

void fio(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
}

void solve(){
	ll r;
	cin >> r;
	cout << r << " " << 1 << endl;
}

signed main()
{
	fio();
	//cin >> t;
	t=1;
	while(t--){
		solve();
	}
	return 0;
}

E.Enigmatic Enumeration

思路:首先确定一个最小的环,假定有个点已经被选中了,那么我们从这个点出发进行bfs将很容易统计答案个数(可以建立dis数组,发现dis[x]+dis[y]+1即为次环的大小(x与y不能是父亲与儿子关系),且x必须走过)。于是我们可以暴力所有点作为必须点进行bfs,然后对已经走过点开个vis标记再记录下,表示这个点不需要用,这样就完成了50%。随后可以想到,如果从一个点再延申出来的一个点的父亲其实不是唯一确定的(因为它可能是所有与他相连的点延申出来的),此时我们分两种情况,当前点编号为id,环最短长度len=dis[id]+dis[x]+1,此时x不是id的父亲,但是dis[x]=dis[faid],此时统计dis等于dis[x]且和id相连的点(必须要走过)的个数,然后答案加上组合数cnt *(cnt-1)/2即可,否则就是统计cn1为与当前id相连且dis等于dis[id]-1的点(必须走过)的个数,cn2等于与目前与id相连且能组成答案为len的点的个数,答案加上cn1 * cn2即可。
注意这里的maxx其实应该是minn,还有每次maxx能减小之前的答案是全作废的

#include<iostream>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<algorithm>
#include<deque>
#include<cctype>
#include<string.h>
#include<math.h>
#include<time.h>
#include<random>
#include<functional>
#include<stack>
#include<string>
#define ll                                long long 
#define lowbit(x) (x & -x)
//#define endl "\n"//                           交互题记得删除
using namespace std;
mt19937 rnd(time(0));
const ll mod = 998244353;
//const ll p=rnd()%mod;
const ll N = 205000;
#define F first
#define S second
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)
		{
			ans = ans % mod * (x % mod) % mod;
		}
		x = x % mod * (x % mod) % mod;
		y >>= 1;
	}
	return ans % mod % mod;
}
ll gcd(ll x, ll y)
{
	if (y == 0)
		return x;
	else
		return gcd(y, x % y);
}
void fio()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
struct s
{
	ll l, r, k;
	friend bool operator<(const s& a, const s& b)
	{
		return a.l > b.r;
	}
};
bool vi[3500], vis[3500];
ll dis[3500];
vector<ll>g[3000 + 5];
int main()
{
	fio();
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= m; i++)
	{
		int l, r;
		cin >> l >> r;
		g[l].push_back(r);
		g[r].push_back(l);
	}
	ll maxx = 1e18;
	ll ans = 0;
	function<void(ll)>bfs = [&](ll x)
		{
			for (ll j = 1; j <= n; j++)vi[j] = 0;
			queue<s>f;
			//ll z=x;
			f.push({ 0,x,0 });
			while (!f.empty())
			{
				ll x = f.front().l;
				ll id = f.front().r;
				ll k = f.front().k;
				f.pop();
				if (vi[id] || vis[id])continue;
				vi[id] = 1;
				dis[id] = x;
				ll cnt = 0;
				ll cn1 = 0;
				for (auto j : g[id])
				{
					if (vi[j] && j != k)
					{
						if (maxx > dis[j] + dis[id] + 1)maxx = dis[j] + dis[id] + 1, cn1 = 1, ans = 0;
						else if (maxx == dis[j] + dis[id] + 1)cn1++;
					}
					if (vi[j] && dis[j] == dis[id] - 1)cnt++;
				}
				if (dis[k] + dis[id] + 1 == maxx)
				{
					ans += cnt * (cnt - 1) / 2;
				}
				else
				{
					ans += cn1 * cnt;
				}
				for (auto j : g[id])
				{
					if (vi[j] || vis[j])continue;
					f.push({ x + 1,j,id });
				}
			}
		};
	for (int i = 1; i <= n; i++)
	{
		bfs(i);
		vis[i] = 1;
	}
	//bfs(1);
	cout << ans << endl;
}

F.Foreign Football

思路::其实我们就是去找合理答案个数,什么时候有合理答案?我们不妨选定一个字符串并枚举前缀的所有可能,显然只要这个长度固定,那么所有答案的长度留固定了,而固定了长度的字符串,那么它的hash值是唯一的,所以开了二维数组pre[i][j],表示第i 个队伍的名字长为j(从前往后)出现次数,显然答案出现时,其pre[i][j]为n-1,那么我们也同时建立个后缀sub[i][j]表示第i个队伍长为j(从后往前)出现次数,显然答案出现时,其sub也为n-1,那么后面我们只需找最短的字符串去爆枚即可(理论上是1e6/n(枚举答案) * (O(n)(问下对应出现次数是否为n-1)+n * n(看下字符串长度是否符合长度标准))。当然我直接枚举了1和2构成的一个字符串也可以过,因为合法字符串有对称性,不可能一个字符串太长且n很大。所以前面的n方检测还是有必要的。

#include<vector>
#include<map>
#include<iostream>
#define endl "\n"
#include<functional>
#include<random>
#include<time.h>
using namespace std;
typedef long long ll;
mt19937 rnd(time(0));
const ll mod = 1e9 + 7;
const ll p = rnd() % mod;
const int INF = 0x3f3f3f3f;
const int N = 2e5 + 5;

void fio() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
}
ll ksm(ll x, ll y)
{
	ll ans = 1;
	while (y)
	{
		if (y & 1)ans = (x * ans) % mod;
		x = (x * x) % mod;
		y >>= 1;
	}
	return ans % mod;
}
vector<ll>pre[501];
vector<ll>sub[501];
vector<ll>sj[501];
ll k[501][501];
ll d[501];
string h[501][501];
void solve()
{
	ll n;
	cin >> n;
	string f;
	ll e = ksm(p, mod - 2);
	map<ll, ll>o;
	ll cnt = 0;
	for (ll i = 1;i <= n;i++)
	{
		for (ll j = 1;j <= n;j++)
		{
			cin >> h[i][j];
			d[i] = max(d[i], (ll)h[i][j].size());
		}
		pre[i].resize(d[i] + 4, 0);
		sub[i].resize(d[i] + 4, 0);
		sj[i].resize(d[i] + 4, 0);
	}
	ll cd = 0;
	for (ll i = 1;i <= n;i++)
	{
		for (ll j = 1;j <= n;j++)
		{
			if (h[i][j].size() != h[j][i].size())cd = 1;
		}
	}
	if (cd)
	{
		cout << "NONE" << endl;
		return;
	}
	for (ll i = 1;i <= n;i++)
	{
		for (ll j = 1;j <= n;j++)
		{
			f = h[i][j];
			if (i != j)
			{
				ll hash = 0;
				for (ll s = 0;s < f.size();s++)
				{
					hash = ((hash * p) % mod + f[s]) % mod;
				}
				ll co = 0;
				ll cs = 0;
				for (ll s = f.size() - 1;s >= 1;s--)
				{
					hash -= f[s];
					if (hash < 0)hash += mod;
					hash = (hash * e) % mod;
					co = co + ((f[s] * ksm(p, cs)) % mod);
					if (co >= mod) co -= mod;
					if (sj[i][s] == hash) pre[i][s]++;
					else  sub[i][s] = 0, pre[i][s] = 0, sj[i][s] = hash, pre[i][s]++;
					//
					if (sj[j][f.size() - s] ==co)sub[j][f.size() - s]++;
					else  sub[j][f.size() - s] = 0, pre[j][f.size() - s] = 0, sj[j][f.size() - s] = co, sub[j][f.size() - s]++;
					cs++;
				}
				k[i][j] = f.size();
			}
		}
	}
	cnt = 0;
	ll of = 0;
	for (ll i = 1;i < k[1][2];i++)
	{
		ll pd = 0;
		if (pre[1][i] == sub[1][i] && pre[1][i] == n - 1)
		{
			for (ll j = 2;j <= n;j++)
			{
				if ((k[j][1] - i) <= 0)pd = 1;
				else
				{
					if (pre[j][k[j][1] - i] == sub[j][k[j][1] - i] && pre[j][k[j][1] - i] == n - 1)
					{
						continue;
					}
					else pd = 1;
				}
				if (pd)break;
			}
			for(ll j=2;j<=n;j++)
			{
				for(ll d=2;d<=n;d++)
				{
					if(j==d)continue;
					if(k[j][1]-i+k[d][1]-i!=k[j][d])pd=1;
				}
			}
			if (pd == 0)
				cnt++, of = i;
			if (cnt >= 2)break;
		}
	}
	if (cnt >= 2)
		cout << "MANY" << endl;
	else if (cnt == 0)
		cout << "NONE" << endl;
	else
	{
		cout << "UNIQUE" << endl;
		cout << h[1][2].substr(0, of) << endl;
		for (ll j = 2;j <= n;j++)
		{
			cout << h[j][1].substr(0, k[j][1] - of) << endl;
		}
	}
}

signed main()
{
	fio();
	ll t;
	t = 1;
	while (t--) {
		solve();
	}
	return 0;
}

G.Graduation Guarantee

思路:队友写的

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rii int
const int N=3e5;
inline rii read() {
   rii x = 0, f = 0;
    char c = getchar();
    while (c > 57 || c < 48) {
        f |= c == 45;
        c = getchar();
    }
    while (c <= 57 && c >= 48) {
        x = (x << 3) + (x << 1) + c - 48;
        c = getchar();
    }
    return f ? -x : x;
}
double ff[5005];
double a[5002][10005]={0};
bool cmp(double& x,double& y){
	return x>y;
}
void solve(){
	int n,k;
	n=read();
	k=read();//初始5002分
	for(int i=1;i<=n;i++){
		scanf("%lf",&ff[i]);
	}
	sort(ff+1,ff+1+n,cmp);
	a[0][5002]=1;
	for(int i=1;i<=n;i++){
		for(int j=5002-i;j<=5002+i;j++){
			a[i][j]=a[i-1][j-1]*ff[i]+a[i-1][j+1]*(1-ff[i]);
		}
	}
	double res=0;
	for(int j=1;j<=n;j++){
		double ans=0;
		for(int i=5002+k;i<=10004;i++){
			ans+=a[j][i];
		}
		res=max(res,ans);
	}
	printf("%.6lf",res);
}
int main(){
	int t=1;
//	t=read();
	while(t--){
		solve();
//		printf("\n");
	}
	
	return 0;
}

H.Highest Hill

思路:队友写的,应该不太难

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rii ll
const int N=3e5;
inline rii read() {
   rii x = 0, f = 0;
    char c = getchar();
    while (c > 57 || c < 48) {
        f |= c == 45;
        c = getchar();
    }
    while (c <= 57 && c >= 48) {
        x = (x << 3) + (x << 1) + c - 48;
        c = getchar();
    }
    return f ? -x : x;
}
ll a[N];
ll r[N];//往右小于
ll l[N];//往左小于
void solve(){
	ll n;
	n=read();
	for(int i=1;i<=n;i++){
		a[i]=read();
	}
	l[1]=0;
	for(int i=2;i<=n;i++){
		if(a[i]>=a[i-1]){
			l[i]=l[i-1]+1;
		}else{
			l[i]=0;
		}
	}
	r[n]=0;
	for(int i=n-1;i>=1;i--){
		if(a[i]>=a[i+1]){
			r[i]=r[i+1]+1;
		}else{
			r[i]=0;
		}
	}
	ll ans=0;
	for(int i=1;i<=n;i++){
		ans=max(ans,min(a[i]-a[i-l[i]],a[i]-a[i+r[i]]));
	}
	printf("%lld",ans);
}
int main(){
	int t=1;
//	t=read();
	while(t--){
		solve();
		printf("\n");
	}
	
	return 0;
}
posted @   长皆  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示