tozangezan's diary

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

ひとり地区予選 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1)

3時間。クッキーチームには勝てなかったけど、一人でこれだけできれば上出来。

A: Alphabet
リス。

char in[52];
int dp[60];
int main(){
	scanf("%s",in);
	int n=strlen(in);
	for(int i=0;i<n;i++){
		dp[i]=max(dp[i],1);
		for(int j=0;j<i;j++){
			if(in[j]<in[i])dp[i]=max(dp[i],dp[j]+1);
		}
	}
	int ret=0;
	for(int i=0;i<n;i++)ret=max(ret,dp[i]);
	printf("%d\n",26-ret);
}

C: Cameras
狼はGreedyをBITでごまかす。

int bit[110000];
int sum(int a,int b){
	if(a)return sum(0,b)-sum(0,a-1);
	int ret=0;
	for(;b>=0;b=(b&(b+1))-1)ret+=bit[b];
	return ret;
}
void add(int a,int b){
	for(;a<110000;a|=(a+1))bit[a]+=b;
}
int main(){
	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<b;i++){
		int p;scanf("%d",&p);p--;
		add(p,1);
	}
	int ret=0;
	for(int i=c-1;i<a;i++){
		if(sum(i-c+1,i)<2){
			if(sum(i,i)){
				ret++;add(i-1,1);
			}else{
				ret++;add(i,1);
				if(sum(i-c+1,i)==1){
					ret++;add(i-1,1);
				}
			}
		}
	}
	printf("%d\n",ret);
}

F: Illumination
2-SAT.

vector<int>g[5100];
vector<int>rev[5100];
int v[5100]; // used twice
int num[5100]; // inverse of conv
int conv[5100]; // dfs order of i-th vertex. note that it's kaerigake ordered
int scc[5100]; // the index of scc containing i-th vertex
int fi[5100]; // the first element of each scc
int ss[5100]; // size of each scc
int cur;
void dfs(int a){
	for(int i=0;i<g[a].size();i++){
		if(v[g[a][i]])continue;
		v[g[a][i]]=1;
		dfs(g[a][i]);
	}
	conv[a]=cur;
	num[cur++]=a;
}
void dfs2(int a){
	scc[a]=cur;
	ss[cur]++;
	for(int i=0;i<rev[a].size();i++){
		if(v[rev[a][i]])continue;
		v[rev[a][i]]=1;
		dfs2(rev[a][i]);
	}
}


int x[1100];
int y[1100];
int main(){
	int a,b,c;
	scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<c;i++){
		scanf("%d%d",x+i,y+i);
	}
	for(int i=0;i<c;i++){
		for(int j=i+1;j<c;j++){
			if(x[i]==x[j]){
				if(ABS(y[i]-y[j])<=2*b){
					g[i*2].push_back(j*2+1);
					g[j*2].push_back(i*2+1);
					rev[i*2+1].push_back(j*2);
					rev[j*2+1].push_back(i*2);
					
				}
			}
			if(y[i]==y[j]){
				if(ABS(x[i]-x[j])<=2*b){
					g[i*2+1].push_back(j*2);
					g[j*2+1].push_back(i*2);
					rev[i*2].push_back(j*2+1);
					rev[j*2].push_back(i*2+1);
				}
			}
		}
	}
	for(int i=0;i<2*c;i++){
		if(v[i])continue;
		v[i]=1;
		dfs(i);
	}
	cur=0;
	for(int i=0;i<c*2;i++)v[i]=0;
	for(int i=c*2-1;i>=0;i--){
		if(v[num[i]])continue;
		v[num[i]]=1;
		fi[cur]=num[i];
		dfs2(num[i]);
		cur++;
	}
	for(int i=0;i<c;i++){
		if(scc[i*2]==scc[i*2+1]){
			printf("NO\n");return 0;
		}
	}
	printf("YES\n");
}

H: Paint
区間のことも頂点だと思う。

long long dp1[410000];
long long dp2[210000];
vector<pair<pair<long long,int> ,int> > ev;

int main(){
	long long a;
	int n;scanf("%I64d%d",&a,&n);
	for(int i=0;i<n;i++){
		long long p,q;scanf("%I64d%I64d",&p,&q);
		p--;
		ev.push_back(make_pair(make_pair(p,1),i));
		ev.push_back(make_pair(make_pair(q,0),i));
		
	}
	std::sort(ev.begin(),ev.end());
	for(int i=0;i<210000;i++)dp2[i]=inf;
	for(int i=0;i<410000;i++)dp1[i]=inf;
	long long now=0;
	long long cur=0;
	for(int i=0;i<ev.size();i++){
		int at=ev[i].second;
		long long ad=ev[i].first.first-now;
		now+=ad;cur+=ad;
		if(ev[i].first.second==1){
			dp2[at]=min(dp2[at],cur);
		}else{
			if(cur>dp2[at]){
				cur=dp2[at];
			}
		}
	}
	cur+=a-now;
	printf("%I64d\n",cur);
}

K: Tournament Wins
算数。

int main(){
	int a,b;scanf("%d%d",&a,&b);
	double ret=0;
	int rem=(1<<a)-b;
	int n=(1<<a);
	for(int i=0;i<a;i++){
		double ks=1;
		int t=(1<<(i+1))-1;
		if(t>rem){
			break;
		}
		for(int j=0;j<t;j++){
			ks*=(double)(rem-j)/(n-1-j);
		}
		ret+=ks;
	}
	printf("%.5f\n",ret);
}

I: Postman
Greedy.

pair<int,int>p[1100];
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		int s,t;scanf("%d%d",&s,&t);
		p[i]=make_pair(s,t);
	}std::sort(p,p+a);
	long long ret=0;
	int tmp=b;

	for(int i=0;i<a;i++){
		if(p[i].first>=0)break;
		if(tmp+p[i].second<=b){
			tmp+=p[i].second;continue;
		}
		int req=p[i].second;
		req-=b-tmp;
		int sk=req/b;
		ret+=(long long)(-p[i].first)*sk;
		req-=sk*b;
		if(req){
			tmp=req;
			ret+=(-p[i].first);
		}else{
			tmp=b;
		}
	}
	tmp=b;
	for(int i=a-1;i>=0;i--){
		if(p[i].first<=0)break;
		if(tmp+p[i].second<=b){
			tmp+=p[i].second;continue;
		}
		int req=p[i].second;
		req-=b-tmp;
		int sk=req/b;
		ret+=(long long)(p[i].first)*sk;
		req-=sk*b;
		if(req){
			tmp=req;
			ret+=(p[i].first);
		}else{
			tmp=b;
		}
	}
	printf("%I64d\n",ret*2);
}

B: Buggy Robot
がんばる

int bfs[60][60][60];
int dx[]={-1,1,0,0};
int dy[]={0,0,-1,1};
char dir[6]="UDLR";
char in[60][60];
char str[60];
int v[60][60][60];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%s",in[i]);
	}
	scanf("%s",str);
	int n=strlen(str);
	int sx,sy,gx,gy;
	for(int i=0;i<a;i++)for(int j=0;j<b;j++){
		if(in[i][j]=='R'){
			sx=i;sy=j;
		}
		if(in[i][j]=='E'){
			gx=i;gy=j;
		}
	}
	for(int i=0;i<a;i++)for(int j=0;j<b;j++)for(int k=0;k<=n;k++){
		bfs[i][j][k]=-1;
	}
	bfs[sx][sy][0]=0;
	deque<pair<pair<int,int>,int> >Q;
	Q.push_back(make_pair(make_pair(sx,sy),0));
	while(Q.size()){
		int row=Q.front().first.first;
		int col=Q.front().first.second;
		int at=Q.front().second;Q.pop_front();
		if(v[row][col][at])continue;
		v[row][col][at]=1;
		if(at<n){
			int tr=row;
			int tc=col;
			for(int i=0;i<4;i++)if(dir[i]==str[at]){
				tr+=dx[i];tc+=dy[i];
			}
			if(tr<0||tr>=a||tc<0||tc>=b||in[tr][tc]=='#'){
				tr=row;tc=col;
			}
			if(bfs[tr][tc][at+1]==-1||bfs[tr][tc][at+1]>bfs[row][col][at]){
				bfs[tr][tc][at+1]=bfs[row][col][at];
				Q.push_front(make_pair(make_pair(tr,tc),at+1));
			}
		}
		for(int i=0;i<4;i++){
			int tr=row+dx[i];
			int tc=col+dy[i];
			if(tr<0||tr>=a||tc<0||tc>=b||in[tr][tc]=='#'){
				tr=row;tc=col;
			}
			if(bfs[tr][tc][at]==-1){
				bfs[tr][tc][at]=bfs[row][col][at]+1;
				Q.push_back(make_pair(make_pair(tr,tc),at));
			}
		}
	}
	int ret=mod;
	for(int i=0;i<=n;i++)ret=min(ret,bfs[gx][gy][i]);
	printf("%d\n",ret);
}

J: Shopping
modで半分になるやつを Sparse Table で高速化。

long long p[210000];
long long st[20][262144];
int fnd(int a,long long b){
	int ret=a;
	for(int i=19;i>=0;i--){
		if(st[i][ret]>b){
			ret+=(1<<i);
		}
		if(ret>=262144)break;
	}
	return ret;
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%I64d",p+i);
	}
	for(int i=0;i<262144;i++){
		for(int j=0;j<20;j++)st[j][i]=inf;
	}
	for(int i=0;i<a;i++){
		st[0][i]=p[i];
	}
	for(int i=1;i<20;i++){
		for(int j=0;j<262144;j++){
			st[i][j]=min(st[i-1][j],j+(1<<(i-1))<262144?st[i-1][j+(1<<(i-1))]:inf);
		}
	}
	while(b--){
		long long v;
		int l,r;
		scanf("%I64d%d%d",&v,&l,&r);
		l--;
		int at=l;
		while(at<r){
			int to=fnd(at,v);
			if(to>=r){
				break;
			}
			v%=p[to];
			at=to;
		}
		printf("%I64d\n",v);
	}
}

L: Windy Path
絶対できる。次に正しく曲がるために一番角度がきついものを選ぶ。

Pt p[60];
int v[60];
char in[60];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++){
		int X,Y;scanf("%d%d",&X,&Y);
		p[i]=Pt(X,Y)*Pt(cos(1),sin(1));
	}

	int st=0;
	for(int i=0;i<a;i++){
		if(p[i].x<p[st].x)st=i;
	}
	scanf("%s",in);
	printf("%d",st+1);
	v[st]=1;
	for(int i=0;i<a-1;i++){
		int to=0;
		if(in[i]=='R')to=1;
		int nx=0;
		for(int j=0;j<a;j++)if(!v[j])nx=j;
		if(to){ // 一番左を選ぶ
			for(int j=0;j<a;j++){
				if(v[j])continue;
				if(iSP(p[st],p[nx],p[j])==1)nx=j;
			}
		}else{ // 一番右を選ぶ
			for(int j=0;j<a;j++){
				if(v[j])continue;
				if(iSP(p[st],p[nx],p[j])==-1)nx=j;
			}
		}
		st=nx;
		v[st]=1;
		printf(" %d",st+1);
	}
	printf("\n");
}

G: Maximum Islands
すでにある陸の周りを海で塗って残りはフロー。LとWを間違えた(は?)。

int dx[]={1,0,-1,0};

int dy[]={0,1,0,-1};
char in[50][50];


const int D_MAX_V=5002;
const int D_v_size=5002;
struct D_wolf{
	int t,c,r;
	D_wolf(){t=c=r=0;}
	D_wolf(int t1,int c1,int r1){
		t=t1;c=c1;r=r1;
	}
};
vector<D_wolf>D_G[D_MAX_V];
int D_level[D_MAX_V];
int D_iter[D_MAX_V];

void add_edge(int from,int to,int cap){
	D_G[from].push_back(D_wolf(to,cap,D_G[to].size()));
	D_G[to].push_back(D_wolf(from,0,D_G[from].size()-1));
}
void D_bfs(int s){
	for(int i=0;i<D_v_size;i++)D_level[i]=-1;
	queue<int> Q;
	D_level[s]=0;
	Q.push(s);
	while(Q.size()){
		int v=Q.front();
		Q.pop();
		for(int i=0;i<D_G[v].size();i++){
			if(D_G[v][i].c>0&&D_level[D_G[v][i].t]<0){
				D_level[D_G[v][i].t]=D_level[v]+1;
				Q.push(D_G[v][i].t);
			}
		}
	}
}
int D_dfs(int v,int t,int f){
	if(v==t)return f;
	for(;D_iter[v]<D_G[v].size();D_iter[v]++){
		int i=D_iter[v];
		if(D_G[v][i].c>0&&D_level[v]<D_level[D_G[v][i].t]){
			int d=D_dfs(D_G[v][i].t,t,min(f,D_G[v][i].c));
			if(d>0){
				D_G[v][i].c-=d;
				D_G[D_G[v][i].t][D_G[v][i].r].c+=d;
				return d;
			}
		}
	}
	return 0;
}
int max_flow(int s,int t){
	int flow=0;
	for(;;){
		D_bfs(s);
		if(D_level[t]<0)return flow;
		for(int i=0;i<D_v_size;i++)D_iter[i]=0;
		int f;
		while((f=D_dfs(s,t,99999999))>0){flow+=f;}
	}
	return 0;
}
int UF[2000];
int FIND(int a){
	if(UF[a]<0)return a;return UF[a]=FIND(UF[a]);
}
void UNION(int a,int b){
	a=FIND(a);b=FIND(b);if(a==b)return;UF[a]+=UF[b];UF[b]=a;
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++)scanf("%s",in[i]);
	for(int i=0;i<a*b;i++)UF[i]=-1;
	for(int i=0;i<a;i++)for(int j=0;j<b;j++){
		if(in[i][j]=='L'){
			for(int k=0;k<4;k++){
				int tr=i+dx[k];
				int tc=j+dy[k];
				if(tr<0||tc<0||tr>=a||tc>=b)continue;
					if(in[tr][tc]=='C')in[tr][tc]='W';
					if(in[tr][tc]=='L'){
						UNION(i*b+j,tr*b+tc);
					}
				
			}
		}
	}
	int ret=0;
	for(int i=0;i<a;i++){
		for(int j=0;j<b;j++){
			if(in[i][j]=='L'&&FIND(i*b+j)==(i*b+j))ret++;
		}
	}
	int S=a*b;
	int T=a*b+1;
	int cnt=0;
	for(int i=0;i<a;i++)for(int j=0;j<b;j++){
		if(in[i][j]=='C'){
			cnt++;
			if((i+j)%2){
				add_edge(S,i*b+j,1);
				for(int k=0;k<4;k++){
					int tr=i+dx[k];
					int tc=j+dy[k];
					if(tr<0||tc<0||tr>=a||tc>=b)continue;
					if(in[tr][tc]=='C'){
						add_edge(i*b+j,tr*b+tc,1);
					}
				}
			}else{
				add_edge(i*b+j,T,1);
			}
		}
	}
	ret+=cnt-max_flow(S,T);
	printf("%d\n",ret);
}

D: Contest Strategy
ひさしぶりに非やるだけを解いた。
t番目の要素ごとに独立で、それぞれに対して dp[i][j][k]: i番目まで見てt番目より大きいものがj回出てきた、すでにt番目が出現したかどうか、を持てばよい。t番目を解くのは、jがK-1以上かつkが1になった最初のタイミング。

long long dp[310][310][2];
int p[310];
int main(){
	int a,b;scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%d",p+i);
	}
	std::sort(p,p+a);
	long long ret=0;
	for(int i=0;i<a;i++){

		long long ks;
		if(a-i<b){
			ks=(a-i)*p[i];
			for(int j=1;j<=a;j++)ks=ks*j%mod;
		//printf("%lld\n",ks);
			ret=(ret+ks)%mod;
			continue;
		}
		ks=0;
		for(int j=0;j<=a;j++)for(int k=0;k<=a;k++)for(int l=0;l<2;l++)
			dp[j][k][l]=0;
		dp[0][0][0]=1;
		for(int j=0;j<a;j++){
			for(int k=0;k<a;k++){
				for(int l=0;l<2;l++){
					if(!dp[j][k][l])continue;
			//		printf("%d %d %d %d: %lld\n",i,j,k,l,dp[j][k][l]);
					if(l==0){
						dp[j+1][k][1]=(dp[j+1][k][1]+dp[j][k][l])%mod;
						if((a-1-i-k)>0)dp[j+1][k+1][0]=(dp[j+1][k+1][0]+dp[j][k][l]*(a-1-i-k))%mod;
						if(i+k-j>0)dp[j+1][k][0]=(dp[j+1][k][0]+dp[j][k][l]*(i+k-j))%mod;
					}else{
						if(k>=b-1)continue;
						
						if((a-1-i-k)>0)dp[j+1][k+1][1]=(dp[j+1][k+1][1]+dp[j][k][l]*(a-1-i-k))%mod;
						if(i+k-j+1>0)dp[j+1][k][1]=(dp[j+1][k][1]+dp[j][k][l]*(i+k-j+1))%mod;
					}
				}
			}
		}
		long long t=1;

		for(int j=a;j>=b;j--){
			for(int k=b-1;k<=a;k++){
				ks=(ks+dp[j][k][1]*(a-j+b)%mod*t)%mod;
			}
			t=t*(a-j+1)%mod;
		}
		ret=(ret+ks*p[i])%mod;
	//	printf("%lld\n",ks*p[i]%mod);
	}
	printf("%lld\n",ret);
}

E: Enclosure
絶対やばいと思うんですが...