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

⚪题和板题大赛/jk

好像能切的样子,但是太菜了,唐了 8 罚。

A - Buy a Pen

输出除去某个颜色以外,其他颜色代表的最大值。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int a,b,c;
string s;
signed main(){
    cin>>a>>b>>c;
    cin>>s;
    if(s[0]=='R') a=1033;
    else if(s[0]=='G') b=1033;
    else c=1033;
    cout<<min(a,min(b,c));
    return 0;
}

B - Right Triangle

给出三个点的坐标,判断该△是不是Rt。

勾股定理。Y1,又踩一次坑。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
int x1,x2,x3,Y1,y2,y3;
int a[100];
int dis(int x1,int Y1,int x2,int y2){
    return (x1-x2)*(x1-x2)+(Y1-y2)*(Y1-y2);
}
signed main(){
    cin>>x1>>Y1>>x2>>y2>>x3>>y3;
    a[0]=dis(x1,Y1,x2,y2),a[1]=dis(x1,Y1,x3,y3),a[2]=dis(x2,y2,x3,y3);
    // sort(a,a+2);
    if(a[0]+a[1]==a[2]||a[1]+a[2]==a[0]||a[2]+a[0]==a[1]) cout<<"Yes";
    else cout<<"No";
    return 0;
}

C - Sum = 0

数列 \(a\) 满足 \(a_i\in[L_i,R_i]\),构造一组 \(a\),使得 \(\sum a_i=0\),或报告无解。

考虑贪心,若 \(l=\sum L_i>0\)\(r=\sum R_i<0\) 显然无解。

否则继续操作,贪心地向 \(0\) 靠近:

  • \(r\ge R_i-L_i\),显然即使将 \(a_i\) 设为 \(L_i\)\(r\) 也大于等于 \(0\),一定是不劣的。
  • 否则,将 \(a_i\) 设为 \(R_i-r\) 即可将当前序列和变成 \(\sum\limits_{i+1\sim r}R_i\),以后的 \(a_i\) 全为 \(R_i\) 即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+3;
int n,l[maxn],r[maxn],sl,sr;
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>l[i]>>r[i];
        sl+=l[i],sr+=r[i];
    }
    if(sl>0||sr<0){
        cout<<"No";
        return 0;
    }
    cout<<"Yes\n";
    for(int i=1;i<=n;i++){
        if(sr==0){ cout<<r[i]<<' ';}
        else if(sr-(r[i]-l[i])>=0){
            cout<<l[i]<<' ';
            sr-=(r[i]-l[i]);
        }else{
            cout<<r[i]-sr<<' '; sr=0;
        }
    }
    return 0;
}

D - Shortest Path 3

给你简单无向图,点有点权,边有边权,求 \(1\) 为源点的最短路。

板子。松弛的时候把点权加进去就行了。

点击查看代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
#define int long long
const int maxn=6e5+3;
const int maxm=4e5+3;
const int inf =0x3f3f3f3f3f3f3f3f;
struct edge{
	int v,w;
	edge(int v=0,int w=0): v(v),w(w){}
};
vector<edge>e[maxn];
#define pb emplace_back
int n,m,s,a[maxn],vis[maxn];
struct di{
	int id,dis;
	di(int id=0,int dis=0): id(id),dis(dis){}
	bool operator<(const di o)const{return dis>o.dis;}
};
priority_queue<di>q;
int dis[maxn];
void dijkstra(){
	for(int i=1;i<=m+n*2;i++)
		dis[i]=inf;
	q.push(di(s,dis[s]=a[s]));
	while(!q.empty()){
		di u=q.top();
		q.pop();
		if(!vis[u.id]){
            vis[u.id]=1;
			for(edge v:e[u.id]){
				if(dis[v.v]>dis[u.id]+v.w+a[v.v]){
					q.push(di(v.v,dis[v.v]=dis[u.id]+v.w+a[v.v]));
				}
			}
		}
	}
	for(int i=2;i<=n;i++){
		cout<<dis[i]<<' ';
	}
}
signed main(){
	cin>>n>>m;s=1;
    for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1,u,v,w;i<=m;i++){
		cin>>u>>v>>w;
		e[u].pb(edge(v,w));
		e[v].pb(edge(u,w));
	}
	dijkstra();
	return 0;
}

E - Count Arithmetic Subsequences

给你一个数列 \(a\),对于 \(\forall i\in[1,n]\) 求长度为 \(i\) 的等差子序列个数。

\(n\le 80,a_i\le 10^9\)

虚空写 DP 传奇(

DP 比较明显,设 \(f_{d,i,k}\) 表示公差为 \(d\),以 \(i\) 为结尾的,长度为 \(k\) 的等差数列数量,则有转移:

\[f_{d,i,k}=\sum\limits_{j=1}^{i-1}[a_i-a_j=d]f_{d,j,k-1} \]

如果每次清空数组,就可以把 \(d\) 一维消去。在枚举过程中累加答案。但是枚举 \(d\) 的时间复杂度巨大,不可通过。

真的吗?

由于 \(n\le 80\),则差的数量上界为 \(\frac{n(n-1)}{2}<320\),所以我们可以把差存起来,直接从里面枚举,而不是枚举值域,最后时间复杂度 \(O(n^4)\)

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353;
int n,a[888],b[888],del[88888],tot,f[888][888],g[888];
int ggg[87888],top;
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            ggg[++top]=a[i]-a[j];
        }
    }
    sort(ggg+1,ggg+top+1);
    int tot=unique(ggg+1,ggg+top+1)-ggg-1;
        for(int i=1;i<=n;i++) f[i][1]=1;
    for(int div=1;div<=tot;div++){
        for(int i=1;i<=n;i++){
        for(int k=2;k<=i;k++)
            for(int j=1;j<i;j++){
                if(a[i]-a[j]==ggg[div])
                    f[i][k]=(f[i][k]+f[j][k-1])%mod;
            }
        }
        for(int i=1;i<=n;i++)
        for(int k=2;k<=i;k++){
            g[k]=(g[k]+f[i][k])%mod;
            f[i][k]=0;
        }
    }
    cout<<n<<' ';
    for(int i=2;i<=n;i++) cout<<g[i]<<' ';
    return 0;
}

F - Perfect Matching on a Tree

给你一棵树,构造方案两两匹配点使得所有匹配点的距离和最大。

看懂了,大概是树形 DP 找重心,以重心为根,然后构造的话就在不同子树内找点连边即得最大,贪心是对的。

时间复杂度 \(O(n)\),有个技巧是先把同一子树内的点排在一起,考虑到重心的性质,每个子树大小不超过 \(\left\lfloor\frac{n}{2}\right\rfloor\),所以将 \(i\)\(i+\left\lfloor\frac{n}{2}\right\rfloor\) 匹配,就能保证这两点不在同一子树内。

点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn=2e5+3;
vector<int>e[maxn];
int n,siz[maxn],rt,f[maxn],ans=0x3f3f3f3f3f3f3f3f,dfn[maxn],dfncnt=-1;
void dfs(int u,int fa,int dep){
    siz[u]=1;
    for(int v:e[u]){
        if(v!=fa){
            dfs(v,u,dep+1);
            siz[u]+=siz[v];
        }
    }
    f[1]+=dep;
}
void dfs1(int u,int fa){
    for(int v:e[u]){
        if(v!=fa){
            f[v]=f[u]+siz[1]-2*siz[v];
            dfs1    (v,u);
        }
    }
    if(ans>f[u]){
        ans=f[u];
        rt=u;
    }
}
void dfs2(int u,int fa,int dep){
    dfn[++dfncnt]=u;
    siz[u]=dep;
    for(int v:e[u]){
        if(v!=fa) dfs2(v,u,dep+1);
    }
}
signed main(){
    cin>>n;
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;
        e[u].emplace_back(v);
        e[v].emplace_back(u);
    }
    dfs(1,0,0);
    dfs1(1,0);
    dfs2(rt,0,0); dfn[++dfncnt]=rt;
    for(int i=1;i<=n/2;i++){
        cout<<dfn[i]<<' '<<dfn[i+n/2]<<'\n';
    }
    return 0;
}

G - Count Substring Query

AC 自动机板题,甚至只要改输入(

绷不住了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+3;
const int maxs=5e5+3;
int n,node,cnt;
char s[maxs],t[maxs];
int trie[maxn][30];
int fail[maxs],word[maxn],sum[maxs],in[maxs];
void insert(){
	int u=0;
	for(int i=0;s[i];i++){
		if(!trie[u][s[i]-'a'])
			trie[u][s[i]-'a']=++node;
		u=trie[u][s[i]-'a'];
	}
	word[++cnt]=u;
}
queue<int>q;
void Fail(){
	for(int i=0;i<26;i++) if(trie[0][i]) q.push(trie[0][i]);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(trie[u][i]) 
				q.push(trie[u][i]),fail[trie[u][i]]=trie[fail[u]][i];
			else trie[u][i]=trie[fail[u]][i];
		}
	}
	for(int i=0;i<=node;i++) in[fail[i]]++;
}
void query(){
	int u=0;
	for(int i=0;t[i];i++){
		u=trie[u][t[i]-'a'];
		sum[u]++;
	}
}
void topo(){
	for(int i=0;i<=node;i++) if(!in[i]) q.push(i);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		sum[fail[u]]+=sum[u];
		if(!--in[fail[u]])
			q.push(fail[u]);
	}
}
signed main(){
	cin>>t; cin>>n;
	for(int i=0;i<n;i++) cin>>s, insert();
	Fail();  query(); topo();
	for(int i=1;i<=n;i++) cout<<sum[word[i]]<<'\n';
	return 0;
} 
posted @ 2024-07-14 23:32  view3937  阅读(27)  评论(0编辑  收藏  举报
Title