tozangezan's diary

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

天下一プログラマーコンテスト2016 予選A

反省点がないので文章はほぼないです。

Irrelevant:

#include<stdio.h>
#include<algorithm>
using namespace std;
int main(){
	int ret=0;
	for(int i=1;i<=100;i++){
		if(i%3&&i%5)ret+=i;
	}
	printf("%d\n",ret);
}
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>g[1100];
int t[1100];
int ret=0;
int mm[1100];
void dfs(int a){
	int tmp=999999;
	if(a==0)tmp=0;
	if(t[a])tmp=t[a];
	else{
		
		for(int i=0;i<g[a].size();i++){
			dfs(g[a][i]);
			tmp=min(tmp,mm[g[a][i]]);
		}
		for(int i=0;i<g[a].size();i++){
			ret+=mm[g[a][i]]-tmp;
		}
	}
	mm[a]=tmp;
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a-1;i++){
		int s;scanf("%d",&s);
		g[s].push_back(i+1);
	}
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);
		t[p]=q;
	}
	dfs(0);
	printf("%d\n",ret);
}
#include<stdio.h>
#include<algorithm>
using namespace std;
int g[30][30];
char A[2100];
char B[2100];
char ans[30];
int g2[30][30];
bool chk(){
	for(int k=0;k<26;k++)for(int i=0;i<26;i++)for(int j=0;j<26;j++)
		g2[i][j]|=(g2[i][k]&g2[k][j]);
	for(int i=0;i<26;i++)for(int j=i+1;j<26;j++)if(g2[i][j]&&g2[j][i])return false;
	return true;
}
int used[30];
int main(){
	int a;scanf("%d",&a);
	bool dame=false;
	for(int i=0;i<26;i++)g[i][i]=1;
	for(int i=0;i<a;i++){
		scanf("%s%s",A,B);
		for(int j=0;A[j];j++){
			if(!B[j]){
				dame=true;break;
			}
			if(A[j]!=B[j]){
				g[A[j]-'a'][B[j]-'a']=1;
				break;
			}
		}
	}
	if(dame){
		printf("-1\n");return 0;
	}
	for(int i=0;i<26;i++)for(int j=0;j<26;j++)g2[i][j]=g[i][j];
	if(!chk()){
		printf("-1\n");return 0;
	}
	for(int i=0;i<26;i++){
		for(int j=0;j<26;j++){
			if(used[j])continue;
			for(int I=0;I<26;I++)for(int J=0;J<26;J++)g2[I][J]=g[I][J];
			for(int k=0;k<26;k++){
				if(!used[k]&&j!=k)g2[j][k]=1;
			}
			if(chk()){
				used[j]=true;
				ans[i]='a'+j;
			//	printf("%c\n",ans[i]);
				break;
			}
		}
	}
	printf("%s\n",ans);
}

D:
適当なことをして座圧するだけ。

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
char in[2];
vector<int>g[30];
long long x[30];
long long y[30];
int dx[]={1,0,-1,0};
int dy[]={0,1,0,-1};
long long p3[32];
void dfs(int a,int b,int c,long long X,long long Y,int d){
	x[a]=X;
	y[a]=Y;
	int t=0;
	for(int i=0;i<g[a].size();i++){
		if(b==g[a][i])continue;
		if(c==t)t++;
		dfs(g[a][i],a,t^2,X+p3[31-d]*dx[t],Y+p3[31-d]*dy[t],d+1);
		t++;
	}
}
long long zx[32];
long long zy[32];
int px[32];
int py[32];
char ret[120][120];
int S[30];
int T[30];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a-1;i++){
		scanf("%s",in);
		int p=in[0]-'A';
		scanf("%s",in);
		int q=in[0]-'A';
		g[p].push_back(q);
		g[q].push_back(p);
		S[i]=p;
		T[i]=q;
	}
	p3[0]=1;
	for(int i=1;i<32;i++)p3[i]=p3[i-1]*3;
	dfs(0,-1,-1,0LL,0LL,0);
	for(int i=0;i<a;i++){
		zx[i]=x[i];
		zy[i]=y[i];
	}
	std::sort(zx,zx+a);
	std::sort(zy,zy+a);
	for(int i=0;i<a;i++){
		px[i]=(lower_bound(zx,zx+a,x[i])-zx)*3;
		py[i]=(lower_bound(zy,zy+a,y[i])-zy)*3;
	}
	for(int i=0;i<100;i++)for(int j=0;j<100;j++)ret[i][j]='.';
	for(int i=0;i<a;i++){
		ret[px[i]][py[i]]='A'+i;
	}
	for(int i=0;i<a-1;i++){
		if(px[S[i]]==px[T[i]]){
			for(int j=min(py[S[i]],py[T[i]])+1;j<max(py[S[i]],py[T[i]]);j++)ret[px[S[i]]][j]='-';
		}else{
			for(int j=min(px[S[i]],px[T[i]])+1;j<max(px[S[i]],px[T[i]]);j++)ret[j][py[S[i]]]='|';
		}
	}
	printf("100 100\n");
	for(int i=0;i<100;i++)printf("%s\n",ret[i]);
}

E:
死ぬほど苦手。一生不可能。

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
vector<pair<int,int> > g[110000];
int gcd(int a,int b){
	while(a){
		b%=a;
		int c=a;a=b;b=c;
	}
	return b;
}
int ABS(int a){return max(a,-a);}
int v[110000];
int d[110000];
int tmp=0;
void dfs(int a,int b,int c){
	//printf("%d %d %d\n",a,b,c);
	d[a]=b;
	v[a]=1;
	for(int i=0;i<g[a].size();i++){
		if(ABS(c)==ABS(g[a][i].second))continue;
		int ad=1;
		if(g[a][i].second<0)ad=-1;
		if(!v[g[a][i].first]){
			
			dfs(g[a][i].first,b+ad,g[a][i].second);
		}else{
		//	printf("%d %d %d %d\n",a,b+1,g[a][i].first,d[g[a][i].first]);
			tmp=gcd(tmp,ABS(b+ad-d[g[a][i].first]));
		}
	}
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);
		g[p].push_back(make_pair(q,i+1));
		g[q].push_back(make_pair(p,-i-1));
	}
	bool dame=false;
	int ret=0;
	for(int i=0;i<a;i++){
		if(v[i])continue;
		tmp=0;
		dfs(i,0,0);
		if(!tmp){dame=true;break;}
	//	printf("%d\n",tmp);
		ret+=tmp;
	}
	if(dame)printf("-1\n");
	else printf("%d\n",ret);
}

result:
4位(□ある人2位)

苦手セットなのに順位はよかったです。

SCPC2016 2차예선

문제1.
별로 너무 어렵지는 않지만 실행 제한시간이 좀 짧다.
적당한 정수배 고속화를 해서 만점을 얻었다.

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
vector<int>id[5100];
int X1[5100];
int X2[5100];
int Y1[5100];
int Y2[5100];
pair<pair<int,int>,int> p[5100];
int main(){
	setbuf(stdout,NULL);
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++){
		int a,b,n;
		scanf("%d%d%d",&a,&b,&n);
		for(int i=0;i<=n;i++)id[i].clear();
		for(int i=0;i<n;i++){
			scanf("%d%d%d%d",X1+i,Y1+i,X2+i,Y2+i);
			p[i]=make_pair(make_pair(X2[i]-X1[i],Y2[i]-Y1[i]),i);
		}
		std::sort(p,p+n);
		int ret=1;
		for(int i=0;i<n;i++){
			int at=p[i].second;
			int tmp=0;
			for(int j=i;j>0;j--){
				for(int k=0;k<id[j].size();k++){
					int to=id[j][k];
					if(X1[at]<=X1[to]&&X2[to]<=X2[at]&&Y1[at]<=Y1[to]&&Y2[to]<=Y2[at]){
						tmp=j;break;
					}
				}
				if(tmp)break;
			}
		//	printf("%d %d\n",at,tmp+1);
			ret=max(ret,tmp+1);
			id[tmp+1].push_back(at);
		}
		printf("Case #%d\n",t);
		printf("%d\n",ret);
	}
}

문제2.
straightforward DP.

#include<stdio.h>
#include<algorithm>
using namespace std;
int b[11000];
int c[11000];
int dp[11000];
int main(){
	setbuf(stdout,NULL);
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++){
		int a;scanf("%d",&a);
		for(int i=0;i<a;i++)scanf("%d",b+i);
		for(int i=0;i<a;i++)scanf("%d",c+i);
		for(int i=0;i<=a;i++)dp[i]=-999999999;
		dp[0]=0;
		for(int i=0;i<a;i++){
			dp[i+1]=max(dp[i+1],dp[i]+b[i]);
			if(i==0)dp[i+1]=max(dp[i+1],dp[i]+c[i]);
			if(i<a-1)dp[i+2]=max(dp[i+2],dp[i]+c[i+1]);
		}
		printf("Case #%d\n",t);
		printf("%d\n",dp[a]);
	}
}

문제3.
'구리'는 무슨 뜻입니까?
유명한 O(n log n) 해법으로는 70점만 얻을 수가 없다.

문제4.
해법은 어렵지 않는데, 힘들게 보인다.

문제5.
I thought there'd been some mistakes in the test data. It was fixed a few hours later.
이분검색. 45도 회전하고 greedy로 소포(=물과 빵)를 할당했다.

#include<stdio.h>
#include<algorithm>
using namespace std;
double x[100];
double y[100];
double p[100];
double X[100];
double Y[100];
double zx[3000];
double zy[3000];
double EPS=1e-9;
double ABS(double a){return max(a,-a);}
int used[100];
int main(){
	setbuf(stdout,NULL);
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++){
		int a,b;scanf("%d%d",&a,&b);
		for(int i=0;i<a;i++){
			scanf("%lf%lf",x+i,y+i);
		}
		for(int i=0;i<b;i++){
			scanf("%lf",p+i);
		}
		std::sort(p,p+b);
		for(int i=0;i<a;i++){
			X[i]=x[i]+y[i];
			Y[i]=x[i]-y[i];
		}
		double LX=999999999;
		double RX=-999999999;
		double LY=999999999;
		double RY=-999999999;
		for(int i=0;i<a;i++){
			LX=min(LX,X[i]);
			RX=max(RX,X[i]);
			LY=min(LY,Y[i]);
			RY=max(RY,Y[i]);
		}
//		printf("%d %d %d %d\n",LX,RX,LY,RY);
		double left=-1;
		double right=11000000;
		for(int i=0;i<50;i++){
			double M=(left+right)/2;
			int sz=0;
			for(int i=0;i<a;i++){
				zx[sz]=X[i]-M;
				zy[sz]=Y[i]-M;
				sz++;
				zx[sz]=X[i]+M;
				zy[sz]=Y[i]+M;
				sz++;
				for(int j=0;j<b;j++){
					if(M+EPS<p[j])continue;
					zx[sz]=X[i]-M+p[j];
					zy[sz]=Y[i]-M+p[j];
					sz++;
					zx[sz]=X[i]+M-p[j];
					zy[sz]=Y[i]+M-p[j];
					sz++;
				}
			}
			std::sort(zx,zx+sz);
			std::sort(zy,zy+sz);
			bool ok=false;
			for(int i=0;i<sz;i++){
				if(ok)break;
				if(i&&zx[i]-zx[i-1]<EPS)continue;
				if(zx[i]+EPS<RX-M||zx[i]>EPS+LX+M)continue;
				for(int j=0;j<sz;j++){
					if(ok)break;
					if(j&&zy[j]-zy[j-1]<EPS)continue;
					if(zy[j]+EPS<RY-M||zy[j]>EPS+LY+M)continue;
					bool dame=false;
					int cnt=0;
					for(int k=0;k<b;k++)used[k]=0;
					for(int k=0;k<a;k++){
						double rem=M-max(ABS(zx[i]-X[k]),ABS(zy[j]-Y[k]));
						if(rem<-EPS){dame=true;break;}
				//		printf("%d %d %d %d: %d\n",M,zx[i],zy[j],k,rem);
						for(int l=b-1;l>=0;l--){
							if(!used[l]&&rem+EPS>p[l]){
								cnt++;
								used[l]=1;
								break;
							}
						}
					}
					if(cnt==b&&!dame){
						ok=true;
					}
				}
			}
			if(ok)right=M;
			else left=M;
		}
		printf("Case #%d\n",t);
		printf("%.1f\n",right+EPS);
	}
}

CODE FESTIVAL 2015 Exhibition B: TRAX

流行のゲーム。


3つのパターンに場合わけして頑張って数えるだけだけど、白と赤がついているせいでうまく数えにくい。
多分こういう系(2次元のグリッドに変なのを並べる方法を数える)の数え上げ得意なんだろうと思う

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
long long mod=1000000007;
int p[110000];
int q[110000];
int r[110000];
int s[110000];
int t[110000];
long long dp[110000][5][2];
long long dp2[110000][5];
int L[2][110000];
int R[2][110000];
int keyL[110000];
int keyR[110000];
vector<int>v[2][110000];
vector<pair<int,int> > v2[110000];
int main(){
	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<c;i++){
		scanf("%d%d%d",p+i,q+i,r+i);
		p[i]--;
		q[i]--;
		r[i]--;
		s[q[i]]|=(1<<(r[i]^(p[i]%2*2)));
		t[p[i]]|=(1<<(r[i]^(q[i]%2*2)));
		v[r[i]%2][q[i]].push_back(p[i]);
		v2[q[i]].push_back(make_pair(p[i],r[i]));
	}
	long long ret=0;
	bool dame=false;
	for(int i=0;i<b;i++){
		if(__builtin_popcount(s[i])>1)dame=true;
	}
	if(!dame){
		if(s[0]){
			for(int i=0;i<4;i++)if(s[0]==(1<<i))dp[1][i][0]=1;
		}else{
			for(int i=0;i<4;i++)dp[1][i][0]=1;
		}
		for(int i=1;i<b;i++){
			for(int j=0;j<4;j++){
				for(int k=0;k<2;k++){
					if(!dp[i][j][k])continue;
					if(s[i]){
						for(int l=0;l<4;l++)if(s[i]==(1<<l)){
							if(l+j==3||l==j)continue;
							int tk=k;
							if(j+1==l){
								tk=1;
							}
							dp[i+1][l][tk]=(dp[i+1][l][tk]+dp[i][j][k])%mod;
						}
					}else{
						for(int l=0;l<4;l++){
							if(l+j==3||l==j)continue;
							int tk=k;
							if(j+1==l){
								tk=1;
							}
							dp[i+1][l][tk]=(dp[i+1][l][tk]+dp[i][j][k])%mod;
						}
					}
				}
			}
		}
		for(int i=0;i<4;i++)ret=(ret+dp[b][i][1])%mod;
	}
//	printf("%lld\n",ret);
	dame=false;
	for(int i=0;i<a;i++)if(__builtin_popcount(t[i])>1)dame=true;
	if(!dame){
		for(int i=0;i<4;i++){
			if(t[0]==0||t[0]==(1<<i)){
				dp2[1][i]=1;
			}
		}
		for(int i=1;i<a;i++){
			for(int j=0;j<4;j++){
				if(!dp2[i][j])continue;
				for(int k=0;k<4;k++){
					if(t[i]==0||t[i]==(1<<k)){
						if((j^k)==1||j==k)continue;
						dp2[i+1][k]=(dp2[i+1][k]+dp2[i][j])%mod;
					}
				}
			}
		}
		for(int i=0;i<4;i++)ret=(ret+dp2[a][i])%mod;
	}
	//printf("%lld\n",ret);
	long long ks=1;
	if(c==0)ks=2;
	int key=0;
	
	//if(key==3)ks=0;
	for(int i=0;i<b;i++){
		L[0][i]=-9999999;
		L[1][i]=9999999;
		if(i){
			keyL[i]|=keyL[i-1];
			L[0][i]=max(L[0][i],L[0][i-1]);
			L[1][i]=min(L[1][i],L[1][i-1]);
		}
		for(int j=0;j<2;j++){
			for(int k=0;k<v[j][i].size();k++){
				if(j==0)L[1][i]=min(L[1][i],v[j][i][k]);
				else L[0][i]=max(L[0][i],v[j][i][k]);
			}
		}
		for(int j=0;j<v2[i].size();j++){
			keyL[i]|=1<<((i^(v2[i][j].first)^(v2[i][j].second/2))%2);
		}
	}
	for(int i=b-1;i>=0;i--){
		R[0][i]=-9999999;
		R[1][i]=9999999;
		if(i<b-1){
			keyR[i]|=keyR[i+1];
			R[0][i]=max(R[0][i],R[0][i+1]);
			R[1][i]=min(R[1][i],R[1][i+1]);
		}
		for(int j=0;j<2;j++){
			for(int k=0;k<v[j][i].size();k++){
				if(j==0)R[0][i]=max(R[0][i],v[j][i][k]);
				else R[1][i]=min(R[1][i],v[j][i][k]);
			}
		}
		for(int j=0;j<v2[i].size();j++){
			keyR[i]|=1<<((i^(v2[i][j].first)^(v2[i][j].second/2))%2);
		}
	}
	for(int i=0;i<b-1;i++){
	//	printf("%d: %d %d %d %d %d %d\n",i,keyL[i],keyR[i+1],L[0][i],L[1][i],R[0][i+1],R[1][i+1]);
		if(__builtin_popcount(keyL[i])>1)continue;
		if(__builtin_popcount(keyR[i+1])>1)continue;
		if(keyL[i]&keyR[i+1])continue;
		ret=(ret+ks*min(a,max(0,min(a,min(L[1][i],R[1][i+1]))-max(0,max(L[0][i],R[0][i+1])))))%mod;
	}
	printf("%lld\n",ret);
}

ICPC2016 国内予選

www.youtube.com

必死に英語の練習をしているのでなんかどうすればいいか教えて

今までちょっと忙しかったけど明日から真面目に動画上げます.......

(こういうタイトル詐欺結構ためらわれる!!!!!!)

Distributed Code Jam 2016 Round 2

通過したのでオンサイトです。去年のFHCもそうだし、こういう解法易実装力本質一発AC難みたいなコンテストはオンラインジャッジ勢にとっては一番希望がありますね。

事前準備とか

今年はある程度は真面目に対策しました。
やったこと

  • ちゃんと環境が動いているか確認する (MinGWを使った)
  • わざわざ使い方を他の場所で調べなくても良いように、コードの雛形を作成
#include<stdio.h>
#include<algorithm>
#include<message.h>
#include"QUESTION NAME HERE.h"
using namespace std;

/*
USER'S GUIDE

Num of data / node: 1000
Amount of data / node: 8MB

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);
*/

int main(){
	
}
  • 過去問のうち正解者が1人以上いる問題の解法の確認

R1に出て得た教訓もあります。

  • Time Limitは結構厳しい(Javaでも通せることが想定されているので、Javaで実行したときにTime Limitが引っかかるような方針かどうかは考慮する)
  • 超危険!!! Memory Limitは要注意。変なSTLを使ったときはちゃんとそのSTLで使うメモリ量を把握しておく。ノマゲでも☆11上位~☆12下位レベル。HARDは核地雷
  • パラメータをいろいろ変えてSmallにresubmitするのが大切

各問題

A:
既出。解決不能。

B:
mod 20ごとに分けて云々。有名問題。

long long mod=1000000007;
long long A[30];
long long B[30];

int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetN();
	
	long long L=(long long)I*N/T;
	long long R=(long long)(I+1)*N/T;
	for(int i=L;i<R;i++){
		A[i%T]+=GetA(i);
		B[i%T]+=GetB(i);
	}
	for(int i=0;i<20;i++){
		A[i]%=mod;
		B[i]%=mod;
	}
	
	if(I){
		for(int i=0;i<T;i++){
			PutLL(0,A[i]);
			PutLL(0,B[i]);
		}
		Send(0);
	}else{
		for(int i=1;i<T;i++){
			Receive(i);
			for(int j=0;j<T;j++){
				A[j]+=GetLL(i);
				B[j]+=GetLL(i);
			}
		}
		for(int i=0;i<T;i++){
			A[i]%=mod;
			B[i]%=mod;
		}
		long long sa=0;
		long long sb=0;
		for(int i=0;i<T;i++){
			sa=(sa+A[i])%mod;
			sb=(sb+B[i])%mod;
		}
		long long ret=sa*sb%mod;
		for(int i=0;i<T;i++){
			ret=(ret+mod-A[i]*B[(T-i)%T]%mod)%mod;
		}
		printf("%lld\n",ret);
	}
}

C:
括弧の対応の様子を+1,-1にして折れ線グラフにする。有名問題。
区間での下方向に飛び出す深さとその深さに最初になる場所、その区間全体での深さの変化を計算する。
あとはノード0から順にデータを隣に流していってダメになったところを見つける。
答えがNになるケースを忘れてて1WA。

int p[10100000];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetLength();
	long long L=(long long)I*N/T;
	long long R=(long long)(I+1)*N/T;
	p[0]=L;
	int at=0;
	int rm=0;
	for(int i=L;i<R;i++){
		char c=GetCharacter(i);
		if(c=='(')at--;
		else at++;
		if(rm<at){
			p[at]=i+1;
			rm=at;
		}
	}
	int st=0;
	if(I){
		Receive(I-1);
		st=GetInt(I-1);
		if(st<0){
			if(I<T-1){
				PutInt((I+1)%T,-114514);
				Send((I+1)%T);
			}
			return 0;
		}
	}
	if(st-rm<0){
		printf("%d\n",p[st+1]-1);
		if(I<T-1){
			PutInt((I+1),-114514);
			Send((I+1));
		}
	}else{
		st-=at;
		if(I<T-1){
			PutInt((I+1)%T,st);
			Send((I+1)%T);
		}else{
			if(st)printf("%d\n",N);
			else printf("-1\n");
		}
	}
}

D:
去年のOnline C (https://code.google.com/codejam/contest/8254486/dashboard#s=p2)と全く同じ方針でDPを並列化する。
上下方向に薄くスライスして、それぞれは左から少しずつ計算しては途中までの結果を上に伝えていく。
結構危ない実装をしている。

char str[320][31000];
int SQ=300;
int dp[320][31000];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int H=GetHeight();
	int W=GetWidth();
	T=min(T,H);
	if(I>=T)return 0;
	int L=H*I/T;
	int R=H*(I+1)/T;
	for(int i=L;i<R;i++){
		for(int j=0;j<W;j++){
			str[i-L][j]=GetPosition(i,j);
		}
	}
	for(int j=0;j<W;j++)str[R-L][j]='0';
	int BL=(W+SQ-1)/SQ;
	for(int i=0;i<320;i++)for(int j=0;j<31000;j++)dp[i][j]=-9999999;
	for(int i=0;i<BL;i++){
		if(I){
			Receive(I-1);
			for(int j=SQ*i;j<SQ*(i+1)&&j<W;j++){
				int t=GetInt(I-1);
				if(str[0][j]!='#')dp[0][j]=max(dp[0][j],t+str[0][j]-'0');
			}
		}else{
			for(int j=SQ*i;j<SQ*(i+1)&&j<W;j++){
				if(str[0][j]!='#')dp[0][j]=str[0][j]-'0';
			}
		}
		for(int j=0;j<R-L;j++){
			for(int k=SQ*i-j;k<SQ*(i+1)+j;k++){
				if(k<0||k>=W)continue;
				if(str[j+1][k]!='#')dp[j+1][k]=max(dp[j+1][k],dp[j][k]+str[j+1][k]-'0');
				if(k&&str[j][k-1]!='#'&&str[j+1][k-1]!='#')dp[j+1][k-1]=max(dp[j+1][k-1],dp[j][k]+str[j][k-1]-'0'+str[j+1][k-1]-'0');
				if(k<W-1&&str[j][k+1]!='#'&&str[j+1][k+1]!='#')dp[j+1][k+1]=max(dp[j+1][k+1],dp[j][k]+str[j][k+1]-'0'+str[j+1][k+1]-'0');
			}
		}
		if(I<T-1){
			if(i){
				for(int j=SQ*(i-1);j<SQ*i;j++){
					PutInt(I+1,dp[R-L][j]);
				}
				Send(I+1);
			}
			if(i==BL-1){
				for(int j=SQ*i;j<W;j++){
					PutInt(I+1,dp[R-L][j]);
				}
				Send(I+1);
			}
		}
	}
	if(I==T-1){
		int ret=-9999999;
		for(int i=0;i<W;i++)ret=max(ret,dp[R-L][i]);
		if(ret<-999)printf("-1\n");
		else printf("%d\n",ret);
	}
}

E:
結局スライド最小値になる。有名問題。
これも区間に分けて、容量が大きくて長い区間の最小値を求めたいときは、事前計算で常にスライドされる中に入っているブロックの最小値を別に求めておいてminをとると。dequeに出し入れされる要素の個数は(区間の長さ)*2くらいになる
dequeはメモリ使用量が大きいのでメモリに無駄がないようにする(無駄に配列に持たない、とか)。

int mv[200];
int main(){
	int T=NumberOfNodes();
	int I=MyNodeId();
	int N=GetNumKms();
	int D=GetTankSize();
	long long L=(long long)N*I/T;
	long long R=(long long)N*(I+1)/T;
	int mm=1000000007;
	for(int i=L;i<R;i++){
		mm=min(mm,(int)(GetGasPrice(i)));
	}
	mv[I]=mm;
	for(int i=0;i<T;i++){
		if(i==I)continue;
		PutInt(i,mm);
		Send(i);
	}
	for(int i=0;i<T;i++){
		if(i==I)continue;
		Receive(i);
		mv[i]=GetInt(i);
	}
	int wa=max(0LL,L-D);
	int wb=max(0LL,R-D);
	int zm=0;
	for(int i=0;i<T;i++){
		if((long long)N*(i+1)/T>wa){
			zm=i;break;
		}
	}
	//printf("%d\n",zm);
	int F=(long long)N*zm/T;
	int G=min((long long)L,(long long)N*(zm+2)/T);
	int ks=1000000007;
	
	for(int i=zm+2;i<I;i++){
		ks=min(ks,mv[i]);
	}
	
	deque<pair<int,int> > Q;
	long long ret=0;
	for(int i=F;i<G;i++){
		if(i<=L-D)continue;
		int ii=GetGasPrice(i);
		if(i>=R-D){
			ks=min(ks,ii);
			continue;
		}
		while(Q.size()&&Q.back().first>=ii){
			Q.pop_back();
		}
		
		Q.push_back(make_pair(ii,i));
	}
	for(int i=L;i<R;i++){
		int ii=GetGasPrice(i);
		while(Q.size()&&Q.back().first>=ii){
			Q.pop_back();
		}
		Q.push_back(make_pair(ii,i));
		while(Q.front().second<=i-D){
			Q.pop_front();
		}
		ret+=min(ks,Q.front().first);
	}
	//printf("%lld %lld: %lld\n",L,R,ret);
	if(I){
		PutLL(0,ret);
		Send(0);
	}else{
		for(int i=1;i<T;i++){
			Receive(i);
			ret+=GetLL(i);
		}
		printf("%lld\n",ret);
	}
}

Result:
全部通って100点、5位でした。
去年のOnline Roundは1点だったので、1年間で点数が100倍になったことになります。このままのペースでいくと、10年後には10000000000000000000000点になります。

AOJ 1256: Crossing Prisms

頑張る。
全面と側面で同じ形であることを知らなくて無駄にコードを書きすぎた。

#include<stdio.h>
#include<algorithm>
#include<vector>
#include<math.h>
using namespace std;
int X[2][5];
int Y[2][5];
int L[20];
int R[20];
double EPS=1e-9;
int ABS(int a){return max(a,-a);}
int main(){
	int a;
	while(scanf("%d",&a),a){
		for(int i=0;i<20;i++){
			L[i]=R[i]=0;
		}
		for(int i=0;i<a;i++)scanf("%d%d",&X[0][i],&Y[0][i]);
		X[0][a]=X[0][0];
		Y[0][a]=Y[0][0];
		for(int i=0;i<a-1;i++){
			if(Y[0][i]==Y[0][i+1]&&Y[0][i+1]==Y[0][i+2]){
				for(int j=i+1;j<a;j++){
					X[0][j]=X[0][j+1];
					Y[0][j]=Y[0][j+1];
				}
				a--;break;
			}
		}
		int b=a;
		for(int i=0;i<=a;i++){
			X[1][i]=X[0][i];Y[1][i]=Y[0][i];
		}
		double ret=0;
		for(int i=0;i<a;i++){
			if(Y[0][i]==Y[0][i+1]){
				L[Y[0][i]]=ABS(X[0][i]-X[0][i+1]);
			}else{
				double ks=sqrt((Y[0][i]-Y[0][i+1])*(Y[0][i]-Y[0][i+1])+(X[0][i]-X[0][i+1])*(X[0][i]-X[0][i+1]))/ABS(Y[0][i]-Y[0][i+1]);
				double tmp=0;
				for(int j=min(Y[0][i],Y[0][i+1]);j<max(Y[0][i],Y[0][i+1]);j++){
					vector<double>now;
					for(int k=0;k<b;k++){
						if(min(Y[1][k],Y[1][k+1])<=j&&j<max(Y[1][k],Y[1][k+1])){
							now.push_back((double)X[1][k]+(double)(X[1][k+1]-X[1][k])*(j+0.5-Y[1][k])/(Y[1][k+1]-Y[1][k]));
						}
					}
					std::sort(now.begin(),now.end());
					for(int k=0;k<now.size();k++){
						if(k%2)tmp+=now[k];
						else tmp-=now[k];
					}
				}
			//	tmp/=2;
				tmp*=ks;
				ret+=tmp;
			}
		}
for(int i=0;i<b;i++){
			if(Y[1][i]==Y[1][i+1]){
				R[Y[1][i]]=ABS(X[1][i]-X[1][i+1]);
			}else{
				double ks=sqrt((Y[1][i]-Y[1][i+1])*(Y[1][i]-Y[1][i+1])+(X[1][i]-X[1][i+1])*(X[1][i]-X[1][i+1]))/ABS(Y[1][i]-Y[1][i+1]);
				double tmp=0;
				for(int j=min(Y[1][i],Y[1][i+1]);j<max(Y[1][i],Y[1][i+1]);j++){
					vector<double>now;
					for(int k=0;k<a;k++){
						if(min(Y[0][k],Y[0][k+1])<=j&&j<max(Y[0][k],Y[0][k+1])){
							now.push_back((double)X[0][k]+(double)(X[0][k+1]-X[0][k])*(j+0.5-Y[0][k])/(Y[0][k+1]-Y[0][k]));
						}
					}
					std::sort(now.begin(),now.end());
					for(int k=0;k<now.size();k++){
						if(k%2)tmp+=now[k];
						else tmp-=now[k];
					}
				}
			//	tmp/=2;
				tmp*=ks;
				ret+=tmp;
			}
		}
		for(int i=0;i<=10;i++){
			vector<double>v;
			for(int j=0;j<a;j++){
				if(min(Y[0][j],Y[0][j+1])<=i&&i<=max(Y[0][j],Y[0][j+1])){
					if(Y[0][j]==Y[0][j+1]){
						v.push_back(X[0][j]);
						v.push_back(X[0][j+1]);
					}else v.push_back((double)X[0][j]+(double)(X[0][j+1]-X[0][j])*(i-Y[0][j])/(Y[0][j+1]-Y[0][j]));
				}
			}
			std::sort(v.begin(),v.end());
			vector<double>V;
			for(int j=0;j<v.size();j++){
				if(j==0||v[j]-v[j-1]>EPS)V.push_back(v[j]);
			}
			double t1=0;
			if(V.size()==4){
				t1=V[3]+V[1]-V[2]-V[0];
			}else if(V.size()>1){
				t1=V[V.size()-1]-V[0];
			}
			vector<double>w;
			for(int j=0;j<b;j++){
				if(min(Y[1][j],Y[1][j+1])<=i&&i<=max(Y[1][j],Y[1][j+1])){
					if(Y[1][j]==Y[1][j+1]){
						w.push_back(X[1][j]);
						w.push_back(X[1][j+1]);
					}else w.push_back((double)X[1][j]+(double)(X[1][j+1]-X[1][j])*(i-Y[1][j])/(Y[1][j+1]-Y[1][j]));
				}
			}
			std::sort(w.begin(),w.end());
			vector<double>W;
			for(int j=0;j<w.size();j++){
				if(j==0||w[j]-w[j-1]>EPS)W.push_back(w[j]);
			}
			double t2=0;
			if(W.size()==4){
				t2=W[3]+W[1]-W[2]-W[0];
			}else if(W.size()>1){
				t2=W[W.size()-1]-W[0];
			}
	//		printf("%f %f\n",t1,t2);
			ret+=L[i]*t2;
			ret+=R[i]*t1;
			ret-=L[i]*R[i];
		}
		printf("%.12f\n",ret);
	}
}

AOJ 2686: Unfair Game

幼稚園児でも解けるような問題だった。

具体的には、

  • A=Bの時
  • 山が一つでA>Bの時
  • 山が一つでA
  • たくさん山があり、A,B>>石の個数の時

を考えてみれば自然と答えは見えてくる。

#include<stdio.h>
#include<algorithm>
using namespace std;
int p[110000];
int main(){
	int n,a,b;
	scanf("%d%d%d",&n,&a,&b);
	for(int i=0;i<n;i++)scanf("%d",p+i);
	if(a>b){
		bool ok=false;
		for(int i=0;i<n;i++)if(p[i]>b)ok=true;
		if(ok)printf("Hanako\n");
		else{
			int tmp=0;
			for(int i=0;i<n;i++)tmp^=p[i];
			if(tmp)printf("Hanako\n");
			else printf("Jiro\n");
		}
	}else if(a==b){
		int tmp=0;
		for(int i=0;i<n;i++)tmp^=p[i]%(a+1);
		if(tmp)printf("Hanako\n");
		else printf("Jiro\n");
	}else{
		int at=-1;
		for(int i=0;i<n;i++){
			if(p[i]>a){
				if(at!=-1){
					printf("Jiro\n");return 0;
				}
				at=i;
			}
		}
		if(at==-1){
			int tmp=0;
			for(int i=0;i<n;i++)tmp^=p[i]%(a+1);
			if(tmp)printf("Hanako\n");
			else printf("Jiro\n");
		}else{
			int tmp=0;
			for(int i=0;i<n;i++)if(at!=i)tmp^=p[i]%(a+1);
			int req=p[at]-tmp;
			if(req<0||req>a||tmp>a)printf("Jiro\n");
			else printf("Hanako\n");
		}
	}
}