「AOJ571~580」の編集履歴(バックアップ)一覧に戻る
AOJ571~580」を以下のとおり復元します。
*571 JJOOII
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0571
百万文字の文字列を読み込んで文字列の中から Jがn個Oがn個Iがn個が連続して並んでいるという条件を満たす部分のうち最大長の文字列を探してその長さを返す問題。
各JOIの連続出現回数をjoiCountsに保存して後は一文字ずつ読み込みながらmodeを変化させていく状態遷移マシンで実装。
手前から読んでJJJ,,,OOO,,,III,,が条件を満たすなら数えるのを継続し満たさないならJがでるまで数えるのをやめるだけである。

競技プログラムの問題は手前からリニアにデータを読んで一つのデータにつき一回の処理で終わりリニアに解を決定できる問題。
なんども複数のデータを照合して突き合わせないと終わらない問題に大別できる。
リニアな問題は簡単なのが多いけどこの問題は典型的なリニアな問題だった。

これ25分くらいで実装できたけど世間様だったらもっと早く実装するのかな。
俺4流プログラマだしよくわかんね。




 #include<stdio.h>
 int main(){
	int joiCounts[3],mode=0,ans=0;
	int c;	
	while(c=getchar()){
		if(c==-1||c=='\n')break;
		if(mode==0){
			if(c=='J'){
				joiCounts[0]=1;
				mode=1;
			}
		}else if(mode==1){
			if(c=='J'){
				joiCounts[0]++;
			}else if(c=='O'){
				joiCounts[1]=1;
				mode=2;
			}else if(c=='I'){
				mode=0;
				joiCounts[0]=0;
			}
		}else if(mode==2){
			if(c=='O'){
				joiCounts[1]++;
				if(joiCounts[1]>joiCounts[0]){
					mode=0;
				}
			}else if(c=='J'){
				mode=1;
				joiCounts[0]=1;
			}else if(c=='I'){
				joiCounts[2]=1;
				mode=3;
				if(joiCounts[1]==1)ans=ans>1?ans:1;
			}
		}else if(mode==3){
			if(c=='I'){
				joiCounts[2]++;
				if(joiCounts[2]==joiCounts[1]){
					ans=ans>joiCounts[2]?ans:joiCounts[2];
				}else if(joiCounts[2]>joiCounts[1]){
					mode=0;
				}
			}else if(c=='J'){
				mode=1;
				joiCounts[0]=1;
			}else if(c=='O'){
				mode=0;
			}
		}
	}
	printf("%d\n",ans);
 }


*572 Card Game is Fun
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0572
単調増加数列の概念を応用して解く。
自由にカードを抜けるAさんのカードをBさんのカードと照合しながら動的計画法で解けばよい。
特に賢く解く部分もないが油断して2回も不合格を食らった問題。
私の場合油断してというパタンが多い。



 #include<stdio.h>
 #include<string.h>
 #include <algorithm>
 int main(){
	int cardsA[5001],cardsB[5001];
	int a,b;
	int memo[5001];
	memset(memo,0,sizeof(memo));
	scanf("%d %d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%d",&cardsA[i]);
	}
	for(int i=0;i<b;i++){
		scanf("%d",&cardsB[i]);
	}
	for(int i=0;i<a;i++){
		for(int j=b-1;j>0;j--){
			if(cardsA[i]==cardsB[j]){
				memo[j]=std::max(memo[j-1]+1,memo[j]);
			}
		}
		for(int j=0;j<b;j++){
			if(cardsA[i]==cardsB[j]){
				memo[j]=std::max(1,memo[j]);
			}
		}
	}
	int ans=0;
	for(int i=0;i<b;i++)ans=std::max(ans,memo[i]);
	printf("%d\n",ans);
 }


*0573 Night Market
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0573
aとbの書き間違いに気づかず不正回を2連続で食らった問題。
問題自体は制限付きの動的計画法で楽々である。
条件の説明がめんどくさい数式で書かれていて読みづらいので入力の解説だけを読んだ方がいい問題。




 #include<stdio.h>
 #include<string.h>
 #include <algorithm>
 int main(){
	int n,t,s,a,b;
	int memo[3001],ans=0;
	memset(memo,0,sizeof(memo));
	scanf("%d %d %d",&n,&t,&s);
	for(int i=0;i<n;i++){
		scanf("%d %d",&a,&b);
		for(int j=t;j>=0;j--){
			int L=j+b;
			if(j<s  && s<L) continue;
			if(L>t)continue;
			memo[L]=std::max(memo[L],memo[j]+a);
			ans=std::max(ans,memo[L]);
		}
	}
	printf("%d\n",ans);
 }






*0574 
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0574
釘の打ちつけられた板に輪ゴムが張られているので何個の釘が輪ゴムに囲まれているかを答える問題。
2列ずつにわけての動的計画法でアセプト。
実装をシンプルにした分速度は出てない。


 #include<stdio.h>
 #include<map>
 #include<algorithm>
 #include<string.h>
 struct P{
	int a,b;
	bool operator<(const P& p)const{
		if(b!=p.b)return b<p.b;//より左側にあり
		return a<p.a;//より上にあり
	}
	bool operator==(const P& p)const{
		return a==p.a&&b==p.b;
	}
 };
 int memo[2][5004];
 std::map<P,int> points;
 std::map<P,int>::iterator it;
 int main(){
	int n,m,x;
	scanf("%d %d",&n,&m);
	P p;
	
	for(int i=0;i<m;i++){
		scanf("%d %d %d",&p.a,&p.b,&x);
		if(points.find(p)==points.end()||points[p]<x+1){
			points[p]=x+1;
		}
	}
	memset(memo,0,sizeof(memo));
	int c,ans=0;
	it=points.begin();
	for(int i=1;i<=n;i++){
		int now=(i+1)&1;
		int old=i&1;
		p.b=i;
		memo[now][i-1]=0;
		for(int j=i;j<=n;j++){
			//0段目としてダミーデータ0を入れてある
			p.a=j;
			if(it!=points.end()&&(*it).first==p){
				c=(*it).second;
				it++;
			}else{
				c=0;
			}
			memo[now][j]=std::max(std::max(c,memo[old][j-1]-1),memo[now][j-1]-1);//斜め左上か斜め右上からの三角形の連続、もしくはこのマスで始まる新しい三角形のどれかで一番大きいのを選ぶ
			if(memo[now][j]!=0)ans++;
		}
	}
	printf("%d\n",ans);
 }


*576 Homework
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0576
宿題の日数を計算する問題。

解法
一番簡単な部類の問題なので何も考えません。

 #include<stdio.h>
 #include<iostream>
 int main(){
 	int L,a,b,c,d;
 	std::cin>>L>>a>>b>>c>>d;
 	a--;
 	b--;
 	std::cout<<(L-1-(a/c>b/d?a/c:b/d))<<"\n";
 }



*577 Unique number
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0577
簡単なゲームのスコアを求める問題。

解法
簡単な問題なので何も考えません。

 #include<stdio.h>
 #include<string.h>
 int main(){
 	int n;
 	int scores[201][3];
 	int memo[3][101];
 	memset(memo,0,sizeof(memo));
 	scanf("%d",&n);
 	for(int i=0;i<n;i++){
 		for(int j=0;j<3;j++){
 			scanf("%d",&scores[i][j]);
 			memo[j][scores[i][j]]++;
 		}
 	}
 	for(int i=0;i<n;i++){
 		int ans=0;
 		for(int j=0;j<3;j++){
 			if(memo[j][scores[i][j]]==1)ans+=scores[i][j];
 		}
 		printf("%d\n",ans);
 	}
 }





*0578 Signboard
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0578
看板の文字を上塗りして看板を再利用する問題。

解法
何も思いつかなかったので全探索しました。
賢い方法というのもあるかもしれません。
等間隔というのが結構難題です。

 #include<stdio.h>
 #include<string.h>
 int main(){
 	int n,baseLen,ans=0;
 	char name[30],old[110];
 	scanf("%d %s",&n,name);
 	baseLen=strlen(name);
 	for(int i=0;i<n;i++){
 		scanf("%s",old);
  		int len=strlen(old);
 		int add=0;
 		for(int j=0;old[j]!='\0';j++){
 			if(add==1)break;
 			for(int k=1;k<len;k++){
 				int count=0;
 				for(int L=0;L*k+j<len;L++){
 					int p=L*k+j;
 					if(name[count]!=old[p])break;
 					count++;
 					if(count>=baseLen)break;
 				}
 				if(count==baseLen)add=1;
 			}
 		}
 		ans+=add;
 	}
 	printf("%d\n",ans);
 }







*0579 Hot days
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0579
毎日の服を選ぶ問題。

解法
条件を満たす服だけで動的計画法を適用すれば解けます。

 #include<stdio.h>
 #include<string.h>
 
 int main(){
 	int d,n,ts[201],as[201],bs[201],cs[201];
 	int memo[201][201];
 	scanf("%d %d",&d,&n);
 	for(int i=0;i<d;i++){
 		scanf("%d",&ts[i]);
 	}
 	memset(memo,-1,sizeof(memo));
 	int t=ts[0];
 	for(int i=0;i<n;i++){
 		scanf("%d %d %d",&as[i],&bs[i],&cs[i]);
 		if(as[i]<=t&&t<=bs[i]){
 			memo[0][i]=0;
 		}
 	}
  	int ans=0;
 	for(int i=1;i<d;i++){
 		int t=ts[i];
 		for(int j=0;j<n;j++){
 			//今日の服j
 			if(t<as[j]||bs[j]<t)continue;
 			int c1=cs[j];
 			for(int k=0;k<n;k++){
 				//前日の服k
 				int base=memo[i-1][k];
 				if(base==-1)continue;
 				int c2=cs[k];
 				int c3=base+(c2>c1?c2-c1:c1-c2);
 				if(memo[i][j]<c3)memo[i][j]=c3;
 				if(ans<c3)ans=c3;
 			}
 		}
 	}
 	printf("%d\n",ans);
 }

復元してよろしいですか?