競プロ参加日記003 東京海上日動 プログラミングコンテスト2020 参加

https://atcoder.jp/contests/tokiomarine2020

●まとめ
A,B,Cの3完で1016位でした。
水色コーダーにとってはC早解きコンテストでしたね

●A問題 Nickname
任意の場所なので、先頭3つを出力すれば良さそうです。
|A|>=|あだ名| なので、制約とか難しいことを考える必要もありません。

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
/*
#include<boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/rational.hpp>
namespace mp = boost::multiprecision;
using Real = mp::number<mp::cpp_dec_float<1024>>;
using Bint = mp::cpp_int;
*/
using namespace std;
#define int long long
#define REP(i,s,e) for((i)=(s);(i)<(e);(i)++)
#define RREP(i,s,e) for((i)=((s)-1);(i)>=(e);(i)--)
#define FOR(i,n) for((i)=(0);(i)<(n);(i)++)
#define RFOR(i,n) for((i)=((n)-1);(i)>=(0);(i)--)
#define MOD 1000000007
signed main(){
   string s;
   cin>>s;
   cout<<s[0]<<s[1]<<s[2]<<endl;
}

●B問題 Tag
鬼は逃げる子供に近づく、逃げる子供は鬼から遠ざかるのが最善手です。
ひたすら一方向に移動したとして、T秒後に位置関係が逆転するかどうかで判定しました。
T<=10^9、V,W<=10^9なので、最大10^18になるのでintだとオーバーフローします。
私は多倍長を使っていますが、long longで大丈夫です。

//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>

#include<boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/rational.hpp>
namespace mp = boost::multiprecision;
using Real = mp::number<mp::cpp_dec_float<1024>>;
using Bint = mp::cpp_int;

using namespace std;
#define int long long
#define REP(i,s,e) for((i)=(s);(i)<(e);(i)++)
#define RREP(i,s,e) for((i)=((s)-1);(i)>=(e);(i)--)
#define FOR(i,n) for((i)=(0);(i)<(n);(i)++)
#define RFOR(i,n) for((i)=((n)-1);(i)>=(0);(i)--)
#define MOD 1000000007
signed main(){
   Bint A,V,B,W,T;
   cin>>A>>V;
   cin>>B>>W;
   cin>>T;
   if(A==B){
       cout<<"YES"<<endl;
   }
   else if(A<B){
       A+=T*V;
       B+=T*W;
       if(A>=B){
          cout<<"YES"<<endl;
       }
       else{
           cout<<"NO"<<endl;
       }
   }
   else{
       A-=T*V;
       B-=T*W;
       if(A<=B){
          cout<<"YES"<<endl;
       }
       else{
           cout<<"NO"<<endl;
       }
   }
}

●C問題 Lamp

1000 10000
0 0 0 0.... 0 1
みたいな入力を観察すれば分かりますが、21手順目くらいで全ての値が1000になります。そこから10000手順目まで値が変化しません。
この問題、実はK手までする必要がなく、早い段階でA[i]のすべての値がNになります。なので、時間制限には思いのほか余裕があります。

それでも、愚直にシミュレーションをするとTLEします。
https://imoz.jp/algorithms/imos_method.html
今回のように、幾つもの区間があって、ある地点iに何個の区間があるかを調べる場合、いもす法を使うとO(N)で求められます。


//#include<bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
/*
#include<boost/multiprecision/cpp_int.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <boost/rational.hpp>
namespace mp = boost::multiprecision;
using Real = mp::number<mp::cpp_dec_float<1024>>;
using Bint = mp::cpp_int;
*/
using namespace std;
#define int long long
#define REP(i,s,e) for((i)=(s);(i)<(e);(i)++)
#define RREP(i,s,e) for((i)=((s)-1);(i)>=(e);(i)--)
#define FOR(i,n) for((i)=(0);(i)<(n);(i)++)
#define RFOR(i,n) for((i)=((n)-1);(i)>=(0);(i)--)
#define MOD 1000000007
#define NMAX 200000
signed main(){   
   int N,K,A[NMAX];
   int a[NMAX];
   cin>>N>>K;
   for(int i=0;i<N;i++){
       cin>>A[i];
   }
   for(int i=0;i<N;i++){
       a[i]=A[i];
   }
   for(int i=0;i<K;i++){
       int n[NMAX]={0};
       int sp=0;
       for(int j=0;j<N;j++){
           if(j-a[j]<0) sp++;
           else n[j-a[j]]++;
           if(j+a[j]+1<N) n[j+a[j]+1]--;
       }
       for(int j=0;j<N;j++){
           sp+=n[j];
           n[j]=sp;
       }
       bool mf=true;
       for(int j=0;j<N;j++){
           a[j]=n[j];
           if(a[j]!=N) mf=false;
       }
       if(mf) break;
   }
   for(int j=0;j<N;j++){
       cout<<a[j]<<" ";
   }
   cout<<endl;
}

※N<=2*10^5はトラップ(NMAX=10^5として1WAしました)

●D問題 Knapsack Queries on a tree
ナップサック問題を何回もする問題。
DPを使えばナップサック自体はO(n*min(V,W))で解けるのですが、それをQ回は明らかに時間が足りません。
メモをうまく残しながら、後半のクエリはさぼる問題と思ったのですが、いいメモ化の仕方が思い浮かばず断念しました。

●まとめ
提出前に制約を確認しよう(こんなミスで1WAは非常にもったいない)

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