見出し画像

ABC183 参戦記録 p.28

itsukiです。
AtCoder Beginner Contest 183 に参戦した様子です。解説記事ではありません。

結果は A, B, C の 3完でした。

考察の流れ

A - ReLU

「関数の定義」を見て一瞬怯む
普通にif文だった
#include <stdio.h>
int main(){
   int x;
   scanf("%d",&x);
   if(x<0){ printf("0\n"); }
   else{ printf("%d\n",x); }
   return 0;
}

B - Billiards

もしかして一次関数?(苦手)
最近解いた ABC181-C を思い出す
一次関数のグラフだとすると、
「跳ね返る前の傾きの -1 倍」=「跳ね返った後の傾き」になる

画像2

入力例1 で考えると、
 前:y = - (1/2)*x + 3/2
 後:y =   (1/2)*x - 3/2
というグラフになる(上図は脳内イメージ)
点 (S_x, S_y) と点 (X, 0) を通るグラフの傾きと、
点 (G_x, G_y) と点 (X, 0) を通るグラフの傾きを考える
(S_y - 0) / (S_x - X) = -1 * (G_y - 0) / (G_x - X) を X について解くと
X = (S_y*G_x + G_y*S_x) / (S_y + G_y) になる
#include <stdio.h>
typedef long long ll;
int main(){
   ll sx, sy, gx, gy;
   double ans;
   scanf("%lld%lld%lld%lld",&sx, &sy, &gx, &gy);
   ans = (double)(sy*gx + gy*sx) / (double)(sy+gy);
   printf("%.10lf\n",ans);
   return 0;
}

C - Travel

最初と最後は「都市1」と固定されているため、
他の全ての都市の順列を考える
最近 ABC150-C を解くために、next_permutation を自作した!これだ!!
本番で next_permutation を使うのが初めてということもあり
非常に手間取るも、なんとか一発AC(この問題だけで1時間超…)
#include <stdio.h>
#include <stdlib.h>
typedef long long ll;
void int_swap(int*a, int*b){ int tmp=(*a); (*a)=(*b); (*b)=tmp; }

void sw_int(int* intgr, int dig){
	int tmp={0},i,j;
	for(i=0, j=dig-1; i<dig/2; i++, j--){
		tmp = intgr[i];
		intgr[i] = intgr[j];
		intgr[j] = tmp;
	}	
}

int next_int_permutation(int arr[], unsigned int n){
	for(int i=n-2; i>=0; i--){
		if( arr[i] < arr[i+1] ){
			int j = n;
			do{
				j--;
			}while( arr[i] >= arr[j] );

			int_swap( &arr[i], &arr[j] );
			sw_int( arr+i+1, n-i-1 );
			return 1;
		}
		if( i==-1 ){
			sw_int( arr, n );	// arr配列を逆順に並び替える
		}
	}
	return 0;
}

int main(){
   int n;
   ll k,cnt=0;
   scanf("%d%lld",&n,&k);
   ll t[10][10]={0};
   for(int i=0; i<n; i++){
       for(int j=0; j<n; j++){
           scanf("%lld", &t[i][j]);
       }
   }
   // 初期順列生成(最初と最後を除く)
   int arr[10]={0};
   for(int i=0; i<n-1; i++){ arr[i]=i+1; }
   //
	do{
       ll sum=0;
       for(int i=0; i<n-1; i++){
           if(i==0){
               sum += t[ 0 ][ arr[i] ];
               sum += t[ arr[i] ][ arr[i+1] ];
           }else if(i==n-1){
               sum += t[ arr[i] ][ 0 ];
           }else{
               sum += t[ arr[i] ][ arr[i+1] ];
           }
       }
       if( sum==k ){ cnt++; }
	}while(next_int_permutation(arr, n-1));	  // 次の順列を生成
	printf("%lld\n", cnt);
	return 0;
}

D - Water Heater

着手した時点で 残り時間 10分… imos 法か?と気づく
最近解いた ABC014-C を思い出すも、実装力が足りず時間切れ

コンテスト後:

#include <stdio.h>
#define Yes()       printf("Yes\n")
#define No()        printf("No\n")
typedef long long ll;
int main(){
	ll i,n,w,s,t,p,max=200005,table[200010]={0};
   scanf("%lld%lld",&n,&w);
   for(i=0; i<n; i++){
       scanf("%lld%lld%lld",&s,&t,&p);
       table[s]+=p;
       table[t]-=p;
   }
   for(i=0; i<max; i++){
       table[i+1] += table[i];
       if( table[i] > w ){ No(); return 0; }
   }
   Yes();
   return 0;
}
そのまま imos 法…! AC したかった…

まとめ

・過去に解いた問題に助けられた
・実装力&早解き力が足りず時間切れで悔しい…早解きの練習をする
・本番で自作 next_permutation を使って AC できたのは嬉しい
・本文中で言及した「ABC181-C」「ABC014-C」については 後ほど記事化(記事化したので追記:2021.05.02)

引き続き、のんびり精進します。

#note初心者 #備忘録 #参戦記録 #AtCoder #ABC #プログラミング #競プロ #C言語 #一次関数 #順列 #imos #累積和

この記事が気に入ったらサポートをしてみませんか?