トヨタ自動車プログラミングコンテスト2024#7(ABC 362)

HaneDaniko發表於2024-07-14

非常好名次,使我的 \(1\) 旋轉

四發罰時應該是這次比賽最唐的東西了,沒有就進前一千了

A.Buy a Pen

特判秒了,懶得打三種 ans=,所以就把不能選的那個賦值成無窮大了

#include<bits/stdc++.h>
using namespace std;
#define speed ios::sync_with_stdio(false);
#define tests int cases;cin>>cases;while(cases--)
int main(){
	speed
	int a,b,c;
	cin>>a>>b>>c;
	string x;
	cin>>x;
	if(x=="Red") a=101;
	if(x=="Green") b=101;
	if(x=="Blue") c=101;
	cout<<min({a,b,c})<<endl;
}

B.Right Triangle

講個好玩的,這個題需要求兩點 \((x_1,y_1),(x_2,y_2)\) 之間的座標,然後我先是寫了個這個

dis[1]=sqrt(x[1]*x[1]+y[1]*y[1]);

後面求勾股定理的時候發現好像不對,這好像是勾股定理,所以改成下面這樣:

dis[1]=sqrt((x[1]-x[2])*(y[1]-y[2]));

這玩意 re 了,我也沒幹別的,唯一想到的就是給負數開根了,一看果然是負的...

#include<bits/stdc++.h>
using namespace std;
#define speed ios::sync_with_stdio(false);
#define tests int cases;cin>>cases;while(cases--)
const double eps=1e-8;
int main(){
	speed
	int x[4],y[4];
	cin>>x[1]>>y[1]>>x[2]>>y[2]>>x[3]>>y[3];
	double dis[4];
	dis[1]=sqrt((x[1]-x[2])*(x[1]-x[2])+(y[1]-y[2])*(y[1]-y[2]));
	dis[2]=sqrt((x[2]-x[3])*(x[2]-x[3])+(y[2]-y[3])*(y[2]-y[3]));
	dis[3]=sqrt((x[3]-x[1])*(x[3]-x[1])+(y[3]-y[1])*(y[3]-y[1]));
//	cout<<dis[1]<<" "<<dis[2]<<" "<<dis[3]<<endl;
	if(dis[3]<dis[1]) swap(dis[3],dis[1]);
	if(dis[3]<dis[2]) swap(dis[3],dis[2]);
	if(abs(dis[1]*dis[1]+dis[2]*dis[2]-dis[3]*dis[3])<=eps) cout<<"Yes"<<endl;
	else cout<<"No"<<endl;'
}

還有一個就是 eps 的問題,這個題刻意卡了直接判等,handmade 測試點會全 WA,不過我恰好改一次都改對了,所以沒吃第二發罰時

C.Sum = 0

稍微有點意思,首先算出所有左邊界的和,再算出所有右邊界的和,注意到左邊界一定是最小的和,而右邊界一定是最大的,因此有解的充要條件應為 \(min\le 0,max\ge 0\)

然後就再掃一遍,從最大的和中減掉(每次都改一個右邊界為左邊界),如果當前最大和減不動了,那就把它減到 \(0\) 輸出,後面的正常輸出右邊界即可.

#include<bits/stdc++.h>
using namespace std;
#define speed ios::sync_with_stdio(false);
#define tests int cases;cin>>cases;while(cases--)
const double eps=1e-8;
#define int long long
int n;
int l[200001],r[200001];
int maxn,minn;
signed main(){
	speed cin>>n;
	for(int i=1;i<=n;++i){
		cin>>l[i]>>r[i];
		maxn+=r[i];
		minn+=l[i];
	}
	if(maxn<0 or minn>0){
		cout<<"No"<<endl;
		return 0;
	}
	cout<<"Yes"<<endl;
	for(int i=1;i<=n;++i){
		if(maxn>0){
			if(maxn>=(r[i]-l[i])){
				maxn-=r[i]-l[i];
				cout<<l[i]<<" ";
			}
			else{
				cout<<r[i]-maxn<<" ";
				maxn=0;
			}
		}
		else if(maxn==0){
			cout<<r[i]<<" ";
		}
	}
}

D.Shortest Path 3

DIJ 版本的考試題,和我考試打的那份錯解一個思路

#include<bits/stdc++.h>
using namespace std;
#define int long long
int cnt;
int n,m,x;
int a[500000];
struct shabicth{
	int q,dat;
	bool operator < (const shabicth &a) const{
		return dat>a.dat;
	}
};
struct node{
	int to,w,next;
}edge[600000];
int head[200010];
bool f[200100];
int dis[200010];
int sum[2000];
int sbcth[7000][3];
void add(int u,int v,int w){
	edge[++cnt].next=head[u];
	edge[cnt].to=v;
	edge[cnt].w=w;
	head[u]=cnt;
}
void dij(int s){
	priority_queue<shabicth> qq;
	int x,y;
	shabicth cc;
	cc.q=s;
	cc.dat=a[s];
	qq.push(cc);
	memset(dis,0x7f,sizeof(dis));
	memset(f,0,sizeof(f));
	dis[s]=a[s];
	while(!qq.empty()){
		x=qq.top().q;
		y=qq.top().dat;
		qq.pop();
		if(!f[x]){
			f[x]=true;
			for(int i=head[x];i;i=edge[i].next){
				cc.q=edge[i].to;
				if(!f[cc.q]&&dis[cc.q]>y+edge[i].w+a[cc.q]){
					dis[cc.q]=y+edge[i].w+a[cc.q];
				    cc.dat=dis[cc.q];
					qq.push(cc);
				}
			}
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		dis[i]=a[i];
	}
	for(int i=1;i<=m;i++){
		int x,y,num;
		cin>>x>>y>>num;
		add(x,y,num);
		add(y,x,num);
	}
	dij(1);
	for(int i=2;i<=n;i++) cout<<dis[i]<<' ';
}

E.Count Arithmetic Subsequences

窩太菜遼,想了半條才明白 Arithmetic Subsequences 是等差數列的意思

日文閱讀理解

上の解法は更に高速化することができます.以下の狀態を持つ DP を考えます.

\(dp[i][l][d]=\) 初項 \(A_i\),長さ \(l(l≥2)\),公差 \(d\) であるような等差數列の個數

\(i\) の降順に見ていき,初項 \(A_i\) を固定します.第 \(2\)\(A_j\ (i<j)\) と長さ \(l\) を全探索します.このとき,公差は \(d=A_j−A_i\) と定まります. \(l=2\) の場合は (\(A_i,A_j\) ) が長さ \(2\) の等差數列なので, \(dp[i][2][d]\)\(1\) を足します. \(l≥3\) の場合,初項 \(A_i\) ,長さ \(l\),公差 \(d\) の等差數列は,初項 \(A_j\) ,長さ \(l−1\),公差 \(d\) の等差數列の先頭に \(A_i\) を追加したものとなっています.よって, \(dp[i][l][d]\)\(dp[j][l−1][d]\) を足します.

公差 \(d\)\(10^9\) 程度の大きな値を取りうるため,\(d\) に関する添字は連想配列で持てばよいです.C++ で map を使用した場合,時間計算量は \(O(N^3logN)\) となります.

または,各 \(i\) についてあり得る公差をあらかじめ列挙して座標圧縮しておけば,\(d\) に関する添字を配列で持つことができます.この場合,時間計算量は \(O(N^3)\) です.

沒用翻譯讀懂了,大概就是開一個 DP 記錄出項,長度,公差三個引數,這樣就能唯一確定一個等差數列,再用 map 判重.

賽時差不多打出來了,因為這個題 \(n\) 只有 \(80\),賽時打的時候我是考慮列舉等差數列前兩項,然後利用公差掃一遍後面的數,統計答案就行了.

此外 \(ans_{1}=n,ans_{2}=\frac{n\times (n-1)}{2}\)

G.Count Substring Query

沒想到考了 AC 自動機板子題,板子不會打就偷了一份

後記

譴責一款強迫我看日文題解的網站

相關文章