返回顶部

Toyota Programming Contest 2024#7(AtCoder Beginner Contest 362)

这场比赛还是比较水的
A,B,C跳过
D题dij把点权和边权都转换为边权即可
E题DP
可以用\(map\)存一下等差数列的差
先说\(O(n^4)\),\(f_{len,i,j,t}\)分别表示长度,现在在\(i\),上一个在\(j\)
显然动态转移方程就有了\(f_{len,i,j,k}=\sum_{k=1}^{k=j-1} f_{len-1,j,k,t}\)

点击查看代码
#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define int long long
using namespace std;
const int N = 85,mod=998244353;
ll n,m,a[N],ans[N];
map <ll,ll> f[N][N][N];
main()
{
	speed();
	cin>>n;
	ll mi=1e9,mx=0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];mi=min(mi,a[i]);
		mx=max(mx,a[i]);
	}
	for(int i=1;i<=n;i++)
	{
//		f[1][i][i][0]=1;
		for(int j=1;j<=i-1;j++)
		{
			f[2][i][j][(ll)(a[i]-a[j])]=1;
		}
	}
	for(int le=3;le<=n;le++)
	{
//		ll ans=0;
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=i-1;j++)
			{
				ll t=a[i]-a[j];
					for(int k=1;k<=j-1;k++)
						if(a[j]-a[k]==t)
							f[le][i][j][t]=(f[le-1][j][k][t]+f[le][i][j][t])%mod;
				ans[le]=(ans[le]+f[le][i][j][t])%mod;
	//			cout<<le<<" "<<f[le][i][j][t]<<endl;
				
			}				
		}	
//		cout<<le<<" "<<ans<<endl;	
	}

	for(int k=1;k<=n;k++)
	{
		if(k==1)cout<<n<<" ";
		else if(k==2)cout<<1ll*n*(n-1)/2<<" ";
		else
		{
//			ll ans=0;
//			for(int i=mi;i<=mx;i++)

			cout<<ans[k]<<" ";
		}
	}
	return 0;
}

然后就水过了,其实我们还可以压缩提下状态,\(map\)结构体
把前三维全部压成一维,代码如下(借的\(qinyun\)对的)

点击查看代码
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef double db;
#define CLOSE() ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
#define GG puts("============================")
#define Ct(x); if(x)puts("Yes");else puts("No");
#define CT(x); if(x)puts("YES");else puts("NO");
#define ct(x); if(x)puts("yes");else puts("no");
#define pii pair<int,int>
#define fi first
#define se second
#define re register
#define int ll
#define pt(x) putchar(x)
#define M(x,y) memset(x,y,sizeof x)

inline ll read()
{
	re ll ans=0;bool f=0;re char ch=getchar();
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())ans=(ans<<1)+(ans<<3)+(ch^48);
	return f?~ans+1:ans;
}

void print(ll n)
{
	if(n<0)putchar('-'),n=-n;
	if(n>9)print(n/10);
	putchar(n%10+48);
}

void _print(ll n)
{
	print(n);
	pt(' ');
}

void __print(ll n)
{
	print(n);
	pt('\n');
}

struct node
{
	int i,d,len;
	bool operator < (const node a) const
	{
		if(i!=a.i)return i<a.i;
		if(d!=a.d)return d<a.d;
		return len<a.len;
	}
	
	
};

const int mod=998244353;
map<node,int>mp;
int a[100],t[100],ans[100];

signed main()
{
	int n=read();
	for(int i=1;i<=n;++i)
		a[i]=read();
	
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<i;++j)
			for(int l=1;l<=n;++l)
			{
				if(l==1)++mp[(node){i,a[i]-a[j],l}],t[l+1]=(t[l+1]+1)%mod;
				else mp[(node){i,a[i]-a[j],l}]=(mp[(node){i,a[i]-a[j],l}]+mp[node{j,a[i]-a[j],l-1}])%mod,t[l+1]=(t[l+1]+mp[node{j,a[i]-a[j],l-1}])%mod;
//				if(l==2)cout<<i<<' '<<j<<' '<<t[3]<<" "<<mp[node{j,a[i]-a[j],l-1}]<<endl;
//				cout<<i<<" "<<j<<' '<<mp[{3,0,1}]<<endl;
			}
	}
	
	_print(n);
	for(int i=2;i<=n;++i)
		_print(t[i]);
	
	return 0;
}
/*
10
1 1 1 1 1 1 1 1 1 1

4
1 1 1 1
*/

F题

Problem Statement

You are given a tree \(T\) with \(N\) vertices. The vertices are numbered \(1\) to \(N\), and the \(i\)-th edge \((1 \leq i \leq N-1)\) connects vertices \(u_i\) and \(v_i\) bidirectionally.

Using \(T\), define a complete graph \(G\) with \(N\) vertices as follows:

  • The weight \(w(x,y)\) of the edge between vertices \(x\) and \(y\) in \(G\) is the shortest distance between vertices \(x\) and \(y\) in \(T\).

Find one maximum weight maximum matching in \(G\). That is, find a set of \(\lfloor N/2 \rfloor\) pairs of vertices \(M=\{(x_1,y_1),(x_2,y_2),\dots,(x_{\lfloor N/2 \rfloor},y_{\lfloor N/2 \rfloor})\}\) such that each vertex \(1,2,\dots, N\) appears in \(M\) at most once, and \(\displaystyle \sum_{i=1}^{\lfloor N/2 \rfloor} w(x_i,y_i)\) is maximized.

Constraints

  • \(2 \leq N \leq 2 \times 10^5\)
  • \(1 \leq u_i ; v_i \leq N\)
  • The input graph is a tree.
  • All input values are integers.

Constraints

  • \(2 \leq N \leq 2 \times 10^5\)
  • \(1 \leq u_i ; v_i \leq N\)
  • The input graph is a tree.
  • All input values are integers.

这是一道找性质的题,样例很水,所以我们需要自己找几组例子

  1. 若两对点形成路径无交点,则交换一对端点更优
  2. 树上两两相交的路径,至少存在一个所有路径的共同交点(因为这是一棵树)

然后题目转换为构造使所有点对形成的路径都经过同一个点\(rt\),并使\(\sum dis(u_i,v_i)\)最大
3. 发现答案仅仅与\(rt\)有关,而他就是树的重心,每个点对的两个数分别属于\(rt\)不同子节点的子树中

树的重心:每个子节点的树的大小都\(<=n/2\),树的重心最有两个,如果一个点不是树的重心,则他的子树存在树的大小\(>n/2\)

点击查看代码
#include <bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
using namespace std;
const int N = 1e6+5;
int n,m;int rt,sz[N],wt[N];
vector <int> G[N],pu[N];
void get(int u,int fa)
{
	sz[u]=1;
	wt[u]=0;
	for(auto to:G[u])
	{
		if(to!=fa)
		{
			get(to,u);
			sz[u]+=sz[to];
			wt[u]=max(wt[u],sz[to]);
		}
	}
	wt[u]=max(wt[u],n-sz[u]);
	if(!rt||wt[u]<wt[rt])rt=u;
}
void dfs(int tg,int u,int f)
{
	for(auto to:G[u])if(to!=f)dfs(tg,to,u);
	
	pu[tg].push_back(u);
}
struct CMP
{
    bool operator()(const int &x,const int &y){
        return pu[x].size()<pu[y].size();
    }	
};
int main()
{
	cin>>n;
	int u,v;
	for(int i=1;i<n;i++)
	{
		cin>>u>>v;
		G[u].push_back(v);
		G[v].push_back(u);
	}
	get(1,0);
	priority_queue <int ,vector<int>,CMP> q;
	for(auto to:G[rt])
	{
		dfs(to,to,rt);q.push(to);
	}
    while(q.size()>1){
        int x=q.top();q.pop();int y=q.top();q.pop();
        cout<<pu[x].back()<<" "<<pu[y].back()<<endl;
        pu[x].pop_back(),pu[y].pop_back();
        if(pu[x].size())q.push(x);
        if(pu[y].size())q.push(y);
    }
    if(q.size()){
        int x=pu[q.top()].back();
        cout<<x<<" "<<rt<<endl;
    }
	return 0;
}

G题
AC自动机板子

posted @ 2024-07-14 08:02  wlesq  阅读(67)  评论(0编辑  收藏  举报