Particle

競技プログラミングについての雑記

Codeforces Round #113 (Div. 2)

A.
成績が良い順にソートして、上からk番目のチームと同じ成績のチームがいくつあるかを答える問題。

struct team{
	int s,t;
	team(int s,int t)
	: s(s), t(t){}
};

bool operator < (const team& a, const team& b)
{
	return a.s < b.s || a.s == b.s && a.t > b.t;
}

map <team,int> data;
priority_queue <team> p;

int main(){
	int n,k;
	cin>>n>>k;
	
	for(int i = 0; i < n; i++){
		int a,b;
		cin>>a>>b;
		team te(a,b);
		
		p.push(te);
		data[te]++;
	}
	
	for(int i = 1; i < k; i++){
		p.pop();
	}
	cout<<data[p.top()]<<endl;
	
	return 0;
}


B.
幾何らしい


C.
単調増加する数列がある。真ん中に来ないといけない数字xがあって、xが中央に来るまで、数字を追加する。
追加する回数の最小値を求めよ。

xより大きい数字、等しい数字、小さい数字の個数をそれぞれ数えれば解けます。xがない場合はxを追加して、xがある場合と同じ処理をします。

xがどの範囲に存在するかを考えて、それの端点が中央にくるようにすれば解けます。

int main(){
	int n,to;
	cin>>n>>to;
	
	int d = 0,u = 0;
	
	for(int i = 0; i < n; i++){
		int a;
		cin>>a;
		if(a<to) d++;
		else if(a>to) u++;
	}
	
	int j = n-d-u,ans = 0;
	if(!j){
		ans++;
		j++;
		n++;
	}
	
	int left = d+1,right = d+j,point = (n+1)/2;
	int r = 0;
	/*入力が小さいので愚直に解く*/
	if(left>point){
		while(left>point){
			r++;
			n++;
			point = (n+1)/2;
		}
	}else while(right<point){
		r++;
		right++;
		n++;
		point = (n+1)/2;
	}
	
	ans += r;
	
	cout<<ans<<endl;
	
	
	return 0;
}


D.
Unopened


E.
点A,B,C,Dがあって、t=0の時に点Dにいる。1秒ごとに現在の点以外に移動する。t=nの時に点Dに戻ってくる経路はいくつあるか。

1 <= n <= 10^7 なのでDP(配列を使わなくても良い)で解けます。

勘違いして、行列を実装しました。実装したことが無かったので勉強になりましたが、コンテストなので、蟻本などを参照したほうが良かったかもしれません。

typedef long long ll;
const ll mod = 1000000007;

struct mat{
	ll a,b,c,d;
	mat(ll a,ll b, ll c, ll d)
	: a(a),b(b),c(c),d(d){}
	
};

void pow(mat &X){
	ll apd = (X.a+X.d) % mod;
	ll bmc = (X.b*X.c) % mod;
	X.b = (X.b*apd)%mod;
	X.c = (X.c*apd)%mod;
	X.a = (X.a*X.a+bmc)%mod;
	X.d = (X.d*X.d+bmc)%mod;
}

void mul(mat &A, const mat &B){
	ll a = A.a;
	ll b = A.b;
	ll c = A.c;
	ll d = A.d;
	A.a = (a*B.a+b*B.c)%mod;
	A.b = (a*B.b+b*B.d)%mod;
	A.c = (c*B.a+d*B.c)%mod;
	A.d = (c*B.b+d*B.d)%mod;
}

int main(){
	
	int n;
	cin>>n;
	n--;
	
	mat A(0,1,3,2);
	mat R(1,0,0,1);
	
	for(;n;n>>=1){
		if(n&1) mul(R,A);
		pow(A);
	}
	cout<<R.c<<endl;
	//cout<<R.a<<' '<<R.b<<' '<<R.c<<' '<<R.d<<endl;
	
	return 0;
}

DPする場合

t=nの時にDにいるような経路の総数をp_n、
A,B,Cにいるようなのをq_nとおくと、

p_0 = 1,q_0 = 0

p_(n+1) = q_n
q_(n+1) = 3*p_n + 2*q_n

となるので、これを実装すれば解けます(説明しませんでしたが、行列の場合はこれを行列にするだけです)。



o-o-o