tozangezan's diary

勝手にソースコードをコピペして利用しないでください。

トロントに行きたいけどGCJは無理そうだからDCJの対策をする狼。四日目。

lispp3 Small

Largeはあまりにも虚無なので無視。
Smallの重要な点は、stackの分散のうまい方法としては、余った部分と不足部分の両方をあつめてくることで、masterで過不足がうまくあっているかを判定できる。
ただしこの問題では問題依存なテクニックが多い(+が少ないときはmasterに送る長さが短くていいとか)ので、応用性に乏しい。
気をつけるべきこととしては、masterを用意する場合は全部で99スレッドになるので、配列長が10100000では足りない。10110000にすると足りる。
smallだからというのもあるが、そこまで罠が多い問題ではない。おすすめもしないけど。

int L_ind[10110000];
char L_ch[10110000];
char R_ch[10110000];
int R_ind[10110000];
int rsz[110];
int lsz[110];
int rind[110][310];
int lind[110][310];
char lst[110][310];
char rst[110][310];
int rnew[110];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetLength();
	if(I==T-1){
		int error=N;
		int perror=N;
		for(int i=0;i<T-1;i++){
			Receive(i);
			int tmp=GetInt(i);
			if(tmp!=-1)perror=min(perror,tmp);
			rnew[i]=GetInt(i);
			rsz[i]=GetInt(i);
			for(int j=0;j<rsz[i];j++){
				rind[i][rsz[i]-1-j]=GetInt(i);
				rst[i][rsz[i]-1-j]=GetCharacter(rind[i][rsz[i]-1-j]);
			}
			lsz[i]=GetInt(i);
			for(int j=0;j<lsz[i];j++){
				lind[i][j]=GetInt(i);
				lst[i][j]=GetCharacter(lind[i][j]);
			}
		}
		int R_sz=0;
		bool ed=false;
		bool R_new=true;
		int prev=-1;
		for(int i=0;i<T-1;i++){
			long long L=(long long)N*i/(T-1);
			long long R=(long long)N*(i+1)/(T-1);
			for(int j=0;j<lsz[i];j++){
				if(R_sz==0){
					error=lind[i][j];
					ed=true;break;
				}
				if(lind[i][j]>prev+1)R_new=false;
				prev=lind[i][j];
				if(lst[i][j]=='+'){
					if(!R_new&&R_ch[R_sz-1]=='('){
						R_ch[R_sz++]='+';
						R_new=true;
					}else{
						error=lind[i][j];ed=true;break;
					}
				}else{
					if((!R_new&&R_ch[R_sz-1]=='+')||(R_new&&R_ch[R_sz-1]=='(')){
						if(!R_new)R_sz-=2;
						else R_sz--;
						R_new=false;
					}else{
						error=lind[i][j];ed=true;break;
					}
				}

			}
			if(ed)break;
			for(int j=0;j<rsz[i];j++){
				if(rind[i][j]>prev+1)R_new=false;
				prev=rind[i][j];
				if(rst[i][j]=='('){
					R_ind[R_sz]=i;
					R_ch[R_sz++]=rst[i][j];
					R_new=true;
				}else if(rst[i][j]=='+'){
					if(!R_new&&R_ch[R_sz-1]=='('){
						R_ch[R_sz++]=rst[i][j];
						R_new=true;
					}
				}
			}
			if(ed)break;
		//	R_ch[R_sz]=0;printf("%d: %s\n",R_new,R_ch);
		}
		error=min(error,perror);
		if(error==N&&R_sz==0)error=-1;
		printf("%d\n",error);
	}else{
		long long L=(long long)N*I/(T-1);
		long long R=(long long)N*(I+1)/(T-1);
		int L_sz=0;
		int R_sz=0;
		bool R_new=false;
		int error=-1;
		for(int i=L;i<R;i++){
			char ch=GetCharacter(i);
			if(ch=='('){
				R_ind[R_sz]=i;
				R_ch[R_sz++]=ch;
				R_new=true;
			}else if(ch=='+'){
				if(R_sz==0){
					L_ind[L_sz]=i;
					L_ch[L_sz++]=ch;
				}else{
					if(!R_new&&R_ch[R_sz-1]=='('){
						R_ind[R_sz]=i;
						R_ch[R_sz++]=ch;
						R_new=true;
					}else{
						error=i;break;
					}
				}
			}else{
				if(R_sz==0){
					L_ind[L_sz]=i;
					L_ch[L_sz++]=ch;
				}else{
					if((!R_new&&R_ch[R_sz-1]=='+')||(R_new&&R_ch[R_sz-1]=='(')){
						if(R_ch[R_sz-1]=='+')R_sz-=2;
						else R_sz--;
						R_new=false;
					}else{
						error=i;break;
					}
				}
			}
		}
		PutInt(T-1,error);
		int se_t=0;
		if(R_new)se_t=1;
		PutInt(T-1,se_t);
		PutInt(T-1,min(210,R_sz));
		for(int i=0;i<min(210,R_sz);i++){
			PutInt(T-1,R_ind[R_sz-1-i]);
		}
		PutInt(T-1,min(210,L_sz));
		for(int i=0;i<min(210,L_sz);i++){
			PutInt(T-1,L_ind[i]);
		}
		R_ch[R_sz]=0;
		L_ch[L_sz]=0;
	//	printf("%s\n",R_ch);
	//	printf("%s\n",L_ch);
		
		Send(T-1);
	}

}

トロントに行きたいけどGCJは無理そうだからDCJの対策をする狼。三日目。

median

これも相当厄介(めんどくささが)。配列がランダムなことからハッシュが有効だというのがわかる。さらに、この問題ではかつてのプラクティスにあったshhhで使ったテクがかなり有効利用できる。
しかしいかんせん実装量が多くて複雑でテストが微妙なので、例によって通るかどうかヒヤヒヤな問題...。なんか一箇所変えたらACになったが。変えた場所がどういう意味を持ってるのかはわからん。
変なマジックナンバーを持ち出したいときはちゃんと素数をもってきましょう。

long long D=1000000000000000LL;
pair<wolf,long long> ev[1100];
int ps[1100];
wolf pk[1100];
int rn[1100000];
int vsz[1100];
int F=33000;
int cnt[40000];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	if(I==T-1){
		for(int i=0;i<1000000;i++){
			rn[i]=GetData((long long)(xrand()%1000000000000000LL));
		}
		std::sort(rn,rn+1000000);
		int Cnt=0;
		for(int i=0;i<1000000;i++){
			if(i&&rn[i]==rn[i-1])Cnt++;
			else Cnt=1;
			if(Cnt>600000){
				printf("%d\n",rn[i]);
				for(int i=0;i<T-1;i++){
					PutInt(i,0);
					Send(i);
				}
				return 0;
			}
		}
		for(int i=0;i<T-1;i++){
			PutInt(i,1);
			Send(i);
		}
		int NK=1000;
		for(int i=0;i<NK;i++){
			long long st=i*1000037;
			wolf key=0;
			wolf ks=1;
			wolf mul=1145141919;
			for(int j=0;j<100;j++){
				key*=mul;
				ks*=mul;
				key+=GetData(D+st+j);
			}
			ev[i]=make_pair(key,st);
		}
		std::sort(ev,ev+NK);
		int sz=0;
		for(int i=0;i<NK;i++){
			if(i==0||ev[i].first!=ev[i-1].first){
				pk[sz]=ev[i].first;
				ps[sz]=ev[i].second;
				sz++;
			}
		}
		for(int i=0;i<T-1;i++){
			PutInt(i,sz);
			for(int j=0;j<sz;j++){
				PutLL(i,pk[j]);
				PutLL(i,ps[j]);
			}
			Send(i);
		}
		long long tot=0;
		for(int i=0;i<T-1;i++){
			Receive(i);
			for(int j=0;j<33000;j++){
				int tmp=GetInt(i);
				cnt[j]+=tmp;
				tot+=tmp;
			}
		}
		long long now=0;
		int pind=0;
		int qind=0;
		for(int i=0;i<33000;i++){
			now+=cnt[i];
			if(now*2>tot){
				pind=i;
				now-=cnt[i];
				break;
			}
		}
		for(int i=0;i<T-1;i++){
			PutInt(i,pind);
			Send(i);
		}
		//tot=0;
		for(int i=0;i<33000;i++)cnt[i]=0;
		for(int i=0;i<T-1;i++){
			Receive(i);
			for(int j=0;j<33000;j++){
				int tmp=GetInt(i);
				cnt[j]+=tmp;
				//tot+=tmp;
			}
		}
		//now=0;
		for(int i=0;i<33000;i++){
			now+=cnt[i];
			if(now*2>tot){
				qind=i;break;
			}
		}
		printf("%d\n",pind*33000+qind);
	}else{
		Receive(T-1);
		int ch=GetInt(T-1);
		if(ch==0)return 0;
		Receive(T-1);
		int sz=GetInt(T-1);
		for(int i=0;i<sz;i++){
			pk[i]=GetLL(T-1);
			ps[i]=GetLL(T-1);
		}
		wolf key=0;
		wolf ks=1;
		wolf mul=1145141919;
		for(int i=0;i<100;i++){
			key*=mul;
			ks*=mul;
			key+=GetData(D+i);
		}
		long long ind=0;
		long long os=0;
		while(1){
			int at=lower_bound(pk,pk+sz,key)-pk;
			if(pk[at]==key){
	//			printf("%d %lld\n",ps[at],ind);
				os=ps[at]-ind;
				break;
			}
			key*=mul;
			key+=GetData(D+ind+100);
			key-=ks*GetData(D+ind);
			ind++;
		}
	//	printf("%lld\n",(os+11)%11);
		int L=sz*I/(T-1);
		int R=sz*(I+1)/(T-1);
		for(int i=L;i<R;i++){
			key=0;
			ks=1;
			mul=1145141919;

			for(int j=0;j<100;j++){
				key*=mul;
				ks*=mul;
				key+=GetData(D+ps[i]-os+j);
			}
			while(1){
				key*=mul;
				key+=GetData(D+ps[i]-os+vsz[i]+100);
				int tmp=GetData(D+ps[i]-os+vsz[i]);
				cnt[tmp/F]++;
				key-=ks*tmp;
				vsz[i]++;
				if(binary_search(pk,pk+sz,key)){
					break;
				}
			}
		}
		for(int i=0;i<33000;i++){
			PutInt(T-1,cnt[i]);
		}
		Send(T-1);
		for(int i=0;i<33000;i++)cnt[i]=0;
		Receive(T-1);
		int tar=GetInt(T-1);
		for(int i=L;i<R;i++){
			for(int j=0;j<vsz[i];j++){
				int tmp=GetData(D+ps[i]-os+j);
		//		printf("%d %lld\n",i,((ps[i]+j)%17+17)%17);
				if(tmp/F==tar)cnt[tmp%F]++;
			}
		}
		for(int i=0;i<33000;i++){
			PutInt(T-1,cnt[i]);
		}
		Send(T-1);
	}
}

トロントに行きたいけどGCJは無理そうだからDCJの対策をする狼。二日目。

baby_blocks

ヤバすぎるTime Limit設定に全アフリカが泣いた。(実は3000万回クエリ読んでも1.8秒しかかからないという罠)
偏りすぎるのがやばいけどどうすんの、ってT個のブロックに等分した後左右から別のブロックに移動するタイミング約2N個をイベントソートして先頭N個だけ使えばいいんですね。
全く難しいアイデアではないし、異様にきつい制限時間だけが厄介。本番でこれ落とした人可哀想www何この11位の人画面の隅に変なキャラクター出しながらコーディングしてるんだけどうけるwwwww

メモ: 司令塔作るときは0番ノードよりT-1番ノードにした方がやりやすい。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<deque>
#include<stack>
#include<string>
#include<string.h>
#include<vector>
#include<set>
#include<map>
#include<bitset>
#include<stdlib.h>
#include<cassert>
#include<time.h>
#include<bitset>
#include<message.h>
#include"baby_blocks.h"
using namespace std;
const long long mod=998244353;
const long long inf=mod*mod;
const long long d2=(mod+1)/2;
const long double EPS=1e-10;
const long double PI=acos(-1.0);
int ABS(int a){return max(a,-a);}
long long ABS(long long a){return max(a,-a);}
long double ABS(long double a){return max(a,-a);}

/*
USER'S GUIDE

Num of data / node: 1000
Amount of data / node: 8MB
Send, Receive / 5 ~ 10ms?
Linear Message passing: slow (500ms through every nodes)

HOW TO USE TOO COMPLICATED AND TOO DIFFICULT LIBRARIES
python dcj/dcj.py test --source QUESTIONNAME.cpp --nodes NUMBER_OF_NODES

FUNCTION LIBRARIES :
int NumberOfNodes();
int MyNodeId();
void PutChar(int target, char value);
void PutInt(int target, int value);
void PutLL(int target, long long value);
void Send(int target); : call this after using Put***
int Receive(int source); call this before using Get*** (return value: number of sended values)
char GetChar(int source);
int GetInt(int source);
long long GetLL(int source);
*/
long long b_sum[110];
long long a_sum[110];
long long l_sum[110];
long long r_sum[110];
int val[10100000];
pair<long long,int> ev[210];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetNumberOfBlocks();
	int bk=T;
	if(N<T){
		T=N+1;
		if(I>=T)return 0;
	}
	
	if(I==T-1){
		for(int i=0;i<T-1;i++){
			Receive(i);
			b_sum[i]=GetLL(i);
		}
		for(int i=0;i<T-1;i++){
			l_sum[i]=r_sum[i]=b_sum[i];
		}
		for(int i=0;i<T-1;i++){
			l_sum[i+1]+=l_sum[i];
		}
		for(int i=T-2;i>=0;i--){
			r_sum[i]+=r_sum[i+1];
		}
		for(int i=0;i<T-1;i++){
			ev[i*2]=(make_pair(l_sum[i],0));
			ev[i*2+1]=(make_pair(r_sum[i],1));
		}
		std::sort(ev,ev+T*2-2);
		long long Loff=0;
		long long Roff=0;
		int l_bl=0;
		int r_bl=T-2;
	//	for(int i=0;i<T;i++){
	//		printf("%lld %d\n",ev[i].first,ev[i].second);fflush(stdout);
	//	}
		for(int i=0;i<T-1;i++){

			PutLL(i,Loff);
			PutLL(i,Roff);
			PutInt(i,l_bl);
			PutInt(i,r_bl);
			Send(i);

			if(ev[i].second==0){
				Loff=ev[i].first;
				l_bl++;
			}else{
				Roff=ev[i].first;
				r_bl--;
			}
		}
		int ret=0;
		for(int i=0;i<T-1;i++){
			Receive(i);
			ret+=GetInt(i);
		}
		printf("%d\n",ret-1);
	}else{
		long long L=(long long)N*I/(T-1);
		long long R=(long long)N*(I+1)/(T-1);
		for(int i=L;i<R;i++){
			int q=GetBlockWeight(i);
			b_sum[I]+=q;
		}
		PutLL(T-1,b_sum[I]);
		Send(T-1);
		Receive(T-1);
		long long Loff=GetLL(T-1);
		long long Roff=GetLL(T-1);
		int l_bl=GetInt(T-1);
		int r_bl=GetInt(T-1);
		long long at_L=(long long)N*l_bl/(T-1);
		long long at_R=(long long)N*(r_bl+1)/(T-1)-1;
		long long n_L=(long long)N*(l_bl+1)/(T-1);
		long long n_R=(long long)N*(r_bl)/(T-1)-1;
		int ret=0;
		while(1){
			if(at_L==n_L||at_R==n_R||at_L>at_R+1)break;
		//	printf("%lld %lld %lld %lld\n",at_L,at_R,n_L,n_R);
			if(Loff==Roff){
				ret++;
				Loff+=GetBlockWeight(at_L);
				at_L++;
				Roff+=GetBlockWeight(at_R);
				at_R--;
			}else if(Loff<Roff){
				Loff+=GetBlockWeight(at_L);
				at_L++;
			}else{
				Roff+=GetBlockWeight(at_R);
				at_R--;
			}
		}
		PutInt(T-1,ret);
		Send(T-1);
	}

}

トロントに行きたいけどGCJは無理そうだからDCJの対策をする狼。一日目。

broken_memory

二分探索で変なところは探せる。3個以上のノードのデータをまとめれば、全ての答えがわかる。
hashingが難しい。2個の間違ったデータを含むときと1個も含まないときでハッシュ値がちゃんと異なるように設定しよう。

#include<stdio.h>
#include<algorithm>
#include<message.h>
#include<set>
#include"broken_memory.h"
using namespace std;

/*
USER'S GUIDE

Num of data / node: 1000
Amount of data / node: 8MB
Send, Receive / 5 ~ 10ms?
Linear Message passing: slow (500ms through every nodes)

HOW TO USE TOO COMPLICATED AND TOO DIFFICULT LIBRARIES
python dcj/dcj.py test --source QUESTIONNAME.cpp --nodes NUMBER_OF_NODES

FUNCTION LIBRARIES :
int NumberOfNodes();
int MyNodeId();
void PutChar(int target, char value);
void PutInt(int target, int value);
void PutLL(int target, long long value);
void Send(int target); : call this after using Put***
int Receive(int source); call this before using Get*** (return value: number of sended values)
char GetChar(int source);
int GetInt(int source);
long long GetLL(int source);
*/
long long in[10100000];
long long xs[10100000];
int fn[1100][2];
int pp[1100];
int ans[1100];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetLength();
	for(int i=0;i<N;i++){
		in[i]=GetValue(i);
		in[i]*=(i*i*9+i*13+14);
		in[i]+=(in[i]<<11)+(in[i]<<22)+(in[i]>>15);
		xs[i+1]=xs[i]^in[i];
	}
	if(I%5==0){
		for(int ii=1;ii<5;ii++){
			int i=I+ii;
			int left=-1;
			int right=N;
			long long tmp=0;
			while(left+1<right){
				int M=(left+right)/2;
				PutInt(i,M);
				Send(i);
				Receive(i);
				long long ff=GetLL(i);
				if(ff!=xs[M+1]){
					right=M;
					tmp=ff;
				}else{
					left=M;
				}
			}
			fn[i][0]=right;
			left=right;
			right=N;
			while(left+1<right){
				int M=(left+right)/2;
				PutInt(i,M);
				Send(i);
				Receive(i);
				long long ff=GetLL(i)^tmp;
				if(ff!=(xs[M+1]^xs[fn[i][0]+1])){
					right=M;
				}else{
					left=M;
				}
			}
			fn[i][1]=right;
			PutInt(i,1145141919);
			Send(i);
		}

		int sz=0;
		for(int ii=1;ii<5;ii++){
			int i=I+ii;
			for(int j=0;j<2;j++){
				pp[sz++]=fn[i][j];
			}
		}
		std::sort(pp,pp+sz);
		for(int i=1;i<sz;i++){
			if(pp[i]==pp[i-1]){
				ans[I]=pp[i];break;
			}
		}
		for(int ii=1;ii<5;ii++){
			int i=I+ii;
			for(int j=0;j<2;j++){
				if(fn[i][j]!=ans[I]){
					ans[i]=fn[i][j];
				}
			}
		}
		if(I==0){
			for(int i=5;i<T;i+=5){
				Receive(i);
				for(int j=0;j<5;j++){
					ans[i+j]=GetInt(i);
				}
			}
			for(int i=0;i<T;i++){
				if(i)printf(" ");
				printf("%d",ans[i]);
			}
			printf("\n");
		}else{
			for(int i=0;i<5;i++){
				PutInt(0,ans[I+i]);
			}
			Send(0);
		}

	}else{
		while(1){
			Receive(I-I%5);
			int at=GetInt(I-I%5);
			if(at==1145141919){
				break;
			}else{
				PutLL(I-I%5,xs[at+1]);
				Send(I-I%5);
			}
		}
	}
}

AGC022Cを解くのが流行っているので流行に乗った

こんなことに時間を使ってないで研究しろ

問題
C - Remainder Game

ソースコード
Submission #2409669 - AtCoder Grand Contest 022


メモ:

15:50 それでは、問題やります
15:52 問題を読んで入力しました(IMEが壊れた...)
15:53 とりあえず各操作は最大1回、greedyに最大のkを決めて好き放題判定していくだけ, nはnかn/2以下にできる
15:54 IMEが壊れてやりにくすぎる、再起動します
15:56 なんかおかしくて再起動ができない
15:58 もどってきました
16:01 最短路のor取るだけな気がしてきた

7 5
3 1

16:04 greedyの2択がめんどいんだよな
16:06 全部管理すれば良い、解けた
16:13 サンプルが通らんよ
16:15 なんでWAなんだよ 2ケースだけだから変なものあるんかな
16:18 どうせ-1のケースでしょ→やっぱりな

典型要素:

  • 2^nで1回ずつ使うやつはgreedy
  • 両側貼り合わせ
  • パソコン操作

両側貼り合わせって要は「スタートからここまで行く方法に関する情報」「ここからゴールまで行く方法に関する情報」をなんかして持っておいて途中の判定とかに使うやつなんですけども、これはAGCでばかり見ます。

圧倒的に遅いんですけども、どこが遅いのかよくわからん(最初のパソコン壊れによる消耗はかなりあるけどもそれでも遅い)。やっぱりAGCはダメですね。

2018年の目標

"一年は目標に始まり反省に終わる。"
  ーー Tozan Southerpacks

書きなぐりと言われても否定できませんが、今年の目標も書いていきましょう。全然意識してないから達成できないんだという話はしてはいけません。

競技プログラミング

枠の数が正常のオンサイトに出る

4年連続でいけたら一流の競技プログラマーでしょ。

なんか大会で優勝する

国内オンサイトかな? ひそかに狙っていきたいと思いますが、ちゃんと個数は確保されるんですかね?

天才以外お断り問題たちに光明を見つける

なんかAGCの問題への見方に変化があると嬉しいですね。

お勉強

研究

1本は雑誌に投稿したいので頑張ります。2本目が収拾つくとなお良いですね。
将来的にどの分野に進みたいかをちゃんと考えられるようにしておこう。

英語

去年はVocabularyの一年でした。当然speakingが今至急なのでspeakingを鍛える。ひとまず海外に行っても研究生活とか困らずできるレベルになるのが目標です(がこんなのどうやって評価すればいいんだ)。
あとwriting、時間との相談要素もありますが、AtCoderの問題文英訳でも関わったりとかもしたい。

他の言語

ロシア語を中級レベル目指そう。なんかあんまり国内で人気のない言語をまともなレベルまでわかるようになろう。

市町村系

また変な場所を目指して旅に出る

ここで言わなくてもやります。

🐺

🐺

いやこれ書く必要ないわ

2017年の反省

"一年は、目標に始まり、反省に終わる。"
  ーー Tozan Southerpacks

冗談はさておき、半ば無茶振りのような今年の目標を一つ一つ振り返っていきましょう。

競技プログラミング

Div1 Hard のAC数を450以上にする

2013年以降の CF の Div1 コンテストは全部 Virtual Participation する

OpenCup にちゃんと出る

ちゃんと出たかな? きわどいところだけど、自分では頑張ったつもりなのでぎりぎり合格点。
最近の目標はjapan02に勝つことですが、自分のできることが限られすぎていて勝敗への影響があんまり大きくないです。安定性への影響はあるかも。

枠の数が正常のオンサイトに出る

DCJ笑 マジ何なんだあれ

自分でも良問と思える問題を3問以上作る

作問は向いてないのがわかったのでもう作問を目標にするのはやめます。

TC Highest 2800以上、CF Highest 2800以上、AtCoder Highest 3200以上

笑 というか笑ってばかりいないでTCとかCFをやれというはなし 絶対真面目にやればこの二つはいけたでしょ

学業

研究して院試して卒業する

多分ヨユー 卒業する前に一本投稿できるとなお良いけど、間に合うか微妙

非ネイティブとしては申し分ない程度の英単語力と、まあ全般的になんとかやっていける程度の英語力をつける

英単語力はもういらんわ 文語的な単語はネイティブと勝負できるね
結局何年経とうとspeaking力だけはどうにかなる下限で選択肢が減りまくりなのでこれだけは何とかしないといけないんだけど何ともできないから助けて
海外のPhDも学校選べば英語力の観点ではspeaking以外は無問題だしspeakingだけ何とかなれば*1もう問題ないでしょ 研究頑張ろう

その他

Youtube 動画...?

時間帯効率が悪い、おふざけ動画垂れ流しのほうが100倍楽。

市町村系とか

四国一周しました
房総一周しました
四国の話はこのブログの変な場所に、房総の話はここに書いてあります(ついでにここにテヘランの話も書いてあります)
やっぱり実際にいくと知見が広がるのでおすすめですが、四国は離島も大切なのでそこが難しいですね。今度は離島に行きたい。

DP未難25

まとめ

競技プログラミングに関しては、やっぱりゴールがないのがなあ。もう半ば引退ムードに近いのですが、この前やり残したこと(国内オンサイト優勝)があることに気づいて、企業コンテストは得意だしせめてそのぐらいは達成してから引退しようという気分です。
あとはまあ語学力と研究と市町村の3つなんですけど、語学力は相も変わらず speaking 力が足を引っ張りすぎていて解決策がなさすぎるのが困りもので (Discordチャンネルにもっと人が欲しいなぁ)、研究はまあ頑張る他なくて、残りは市町村ですかね。市町村に関しては、また未踏の地に行きたいですね。予定では来年の春には三陸に遊びに行く予定です。

*1:なっていません。IELTS 6.0です。