今日解いた問題たち⑩

ICPCからの現実逃避のためにCodeforcesのcombinatoricsをまたやってみました。前回からしばらく空いていたので、そのあいだに埋めていないsolvedの多い問題も増えていました。

353B: Two Heaps
Greedyつらい。

#include<stdio.h>
#include<algorithm>
using namespace std;
int b[200];
int c[200];
int d[100];
int e[100];
pair<int,int> dat[100];
int main(){
	int a;
	scanf("%d",&a);
	for(int i=0;i<2*a;i++){
		scanf("%d",b+i);
	}
	int now=0;
	for(int i=10;i<=99;i++){
		int v=0;
		for(int j=0;j<2*a;j++){
			if(i==b[j]){
				v++;
			}
		}
		dat[i-10]=make_pair(v,i);
	}
	std::sort(dat,dat+90);
	for(int i=0;i<90;i++){
		int T=dat[i].second;
		for(int j=0;j<2*a;j++){
			if(T==b[j]){
				c[j]=(++now)%2;
				if(now%2==0)d[T]=1;
				else e[T]=1;
			}
		}
	}
	int A=0;
	int B=0;
	for(int i=0;i<100;i++){
		if(d[i])A++;
		if(e[i])B++;
	}
	printf("%d\n",A*B);
	for(int i=0;i<2*a;i++){
		if(i)printf(" ");
		printf("%d",c[i]+1);
	}
	printf("\n");
}

340B: Maximal Area Quadrilateral
これはcombinatoricsじゃないけど。三角形の符号付面積。最高に頭が悪く、無駄にlogをつけてしまい時間が危ない。

#include<stdio.h>
#include<algorithm>
using namespace std;
double x[500];
double y[500];
double s[500];
int main(){
	int a;
	scanf("%d",&a);
	for(int i=0;i<a;i++){
		scanf("%lf%lf",x+i,y+i);
	}
	double ret=0;
	for(int i=0;i<a;i++){
		for(int j=i+1;j<a;j++){
			int N=0;
			for(int k=0;k<a;k++){
				if(k==i)continue;
				if(k==j)continue;
				s[N++]=(x[k]-x[i])*(y[j]-y[i])-(x[j]-x[i])*(y[k]-y[i]);
			}
			std::sort(s,s+a-2);
			ret=max(ret,s[a-3]-s[0]);
		}
	}
	printf("%.12f\n",ret/2);
}

151D
同じ問題を2回も解いちゃったじゃないか!!

145C: Lucky Subsequence
Lucky Numberは少ないので、それだけについてDPしてからほかのと合わせる。こういうのはluckynumber系そのものになれる必要がある気がする…

#include<stdio.h>
#include<algorithm>
using namespace std;
int c[100010];
int mod=1000000007;
long long dp[2501][2501];
int S[2500];
long long inv[300000];
int main(){
	int a,b;
	scanf("%d%d",&a,&b);
	for(int i=0;i<a;i++){
		scanf("%d",c+i);
	}
	inv[1]=1;
	for(int i=2;i<300000;i++){
		inv[i]=(mod-(mod/i)*inv[mod%i]%mod)%mod;
	}
	std::sort(c,c+a);
	int ind=0;
	int d=0;
	for(int i=0;i<a;i++){
		bool ok=true;
		int p=c[i];
		while(p){
			if(p%10!=4&&p%10!=7)ok=false;
			p/=10;
		}
		if(ok){
			if(i==0||c[i]!=c[i-1]){
				ind++;
				S[ind-1]++;
			}else{
				S[ind-1]++;
			}
		}else d++;
	}
	dp[0][0]=1;
	for(int i=0;i<ind;i++){
		for(int j=0;j<ind;j++){
			dp[i+1][j]=(dp[i+1][j]+dp[i][j])%mod;
			dp[i+1][j+1]=(dp[i+1][j+1]+dp[i][j]*S[i])%mod;
		}
	}
	long long ret=0;
	long long now=1;
	for(int i=0;i<=b;i++){
		ret=(ret+now*dp[ind][b-i]%mod)%mod;
		if(d==i)break;
		now=now*(d-i)%mod*inv[i+1]%mod;
//		printf("%lld ",now);
	}
	printf("%lld\n",ret);
}

lldを適宜I64dに直してください。コメント内のも直してください。