tozangezan's diary

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

Codeforces Round #380 (Div. 1, Rated, Based on Technocup 2017 - Elimination Round 2)

なぜに6問...充実しすぎて2時間でやるなら5問でも十分だと思えるセット。

A B C D E F Place
00:19 00:28 00:37 01:49 (+2) - - 34th

A:
Aですらいつもより難しい。短すぎるものを除けば一次式になるのでうんたらかんたら

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
pair<int,int> p[210000];
int f[210000];
int g[210000];

int main(){
	int a,b,c,d;
	scanf("%d%d%d%d",&a,&b,&c,&d);
	int ret=mod;
	for(int i=0;i<a;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		p[i]=make_pair(y,x);
	}
	std::sort(p,p+a);
	for(int i=0;i<b;i++)scanf("%d",f+i);
	f[b]=c;
	std::sort(f,f+b+2);
	for(int i=0;i<b+1;i++){
		g[i]=f[i+1]-f[i];
	}
	std::sort(g,g+b+1);
	b++;
	int at=0;
	long long tn=0;
	long long al=0;
	for(int i=0;i<b;i++)tn+=g[i];
	tn*=3;
	for(int i=0;i<a;i++){
		if(g[b-1]>p[i].first)continue;
		while(at<b&&g[at]*2<=p[i].first){
			tn-=3LL*g[at];
			al+=g[at];
			at++;
		}
		long long cost=al+tn-(long long)(b-at)*p[i].first;

		//printf("%d: %d %I64d %d %d\n",i,at,tn,al,cost);
		if(cost<=d)ret=min(ret,p[i].second);
	}
	if(ret==mod)ret=-1;
	printf("%d\n",ret);
}

B:
左から戦艦の長さごとに漁っていくと残り候補が減っていく。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
char in[210000];
int main(){
	int a,b,c,d;
	scanf("%d%d%d%d",&a,&b,&c,&d);
	scanf("%s",in);
	int rem=0;
	int ren=0;
	for(int i=0;i<a;i++){
		if(in[i]=='0'){
			ren++;
		}else{
			rem+=ren/c;
			ren=0;
		}
	}
	rem+=ren/c;
	vector<int>ret;
	ren=0;
	for(int i=0;i<a;i++){
		if(rem<b)break;
		if(in[i]=='0'){
			ren++;
			if(ren%c==0){
				ret.push_back(i+1);
				rem--;
			}
		}else{
			ren=0;
		}
	}
	printf("%d\n",(int)(ret.size()));
	for(int i=0;i<ret.size();i++){
		if(i)printf(" ");
		printf("%d",ret[i]);
	}printf("\n");
}

C:
nがあるなら1~n-1が全部揃っているので、nを全部試す。他所に0があるとか0のあるべきところに0が入ってないとか、変なケースが多い。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int c[210000];
int d[210000];
int z[210000];
int sum[210000];
int main(){
	int a,b;scanf("%d%d",&a,&b);b--;
	if(a==1){
		printf("0\n");return 0;
	}
	for(int i=0;i<a;i++)scanf("%d",c+i);
	int ba=0;
	int f=0;
	for(int i=0;i<a;i++){
		if(b==i&&c[i]){
			ba++;
		}else if(b!=i&&c[i]==0){
			//ba++;
			f++;
		}else{
			d[c[i]]++;
		}
	}
	int ret=88888888;
	for(int i=1;i<a;i++){
		z[i]=z[i-1];
		if(!d[i])z[i]++;
	}
	for(int i=a-1;i>0;i--){
		sum[i]=sum[i+1]+d[i];
	}
	for(int i=1;i<a;i++){
		int t=f+sum[i+1];
		int tot=max(t,z[i]);
		ret=min(ret,ba+tot);
	}
	printf("%d\n",ret);
}

D:
実は状態数が少ない(取ったカードの枚数の差がk以下、kもO(N^0.5))ので普通にDPすればよい。
遷移先とかを間違えていて本番だったら落ちてた。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int b[4100];
int sum[4100];
int dp[4100][200][100];
int K=95;
int ABS(int a){
	return max(a,-a);
}
int N;
int calc(int a,int b,int c){
	//if(a<0||b+K<0||c<0)printf("dame\n");
	///if(a>=4100||b+K>=200||c>=100)printf("dame\n");
	
	if(dp[a][b+K][c]!=-mod)return dp[a][b+K][c];
	int s=a;int t=a+b;
	int L=a;
	int R=N-a-b;
	if(R-L<c){
		return dp[s][t-s+K][c]=0;
	}
	int ret=-mod;
	if(s<=t){
		if(L+c+1<=R){
			ret=max(ret,-calc(s+c+1,t-(s+c+1),c+1)+sum[L+c+1]-sum[L]);
		}
		ret=max(ret,-calc(s+c,t-s-c,c)+sum[L+c]-sum[L]);
	}else{
		if(L+c+1<=R){
			ret=max(ret,-calc(s,t+c+1-s,c+1)+sum[R]-sum[R-c-1]);
		}
		ret=max(ret,-calc(s,t+c-s,c)+sum[R]-sum[R-c]);
	}
	//if(s<0||t-s+K<0||c<0)printf("%d %d %d: %d\n",s,t-s+K,c,ret);
	return dp[s][t-s+K][c]=ret;
}
int main(){
	int a;scanf("%d",&a);
	N=a;
	for(int i=0;i<a;i++)scanf("%d",b+i);
	for(int i=0;i<a;i++)sum[i+1]=sum[i]+b[i];
	for(int i=0;i<4100;i++)for(int j=0;j<200;j++)for(int k=0;k<100;k++)
		dp[i][j][k]=-mod;
	printf("%d\n",calc(0,0,1));
}

E:
フローでできることの範疇を超えている気がする。また今度。

SRM 704

7ヶ月ぶりにTopCoderに出た。

300:
これはAGC005のCと全く同じ。

// I like wolves!!
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <string.h>
#include <complex>
using namespace std;
 
class TreeDistanceConstruction {
	public:
	int v[110];
	int e[110];
	vector <int> construct(vector <int> d) {
		int n=d.size();
		int c=0;
		for(int i=0;i<110;i++)v[i]=0;
		for(int i=0;i<n;i++)c=max(c,d[i]);
		int cnt=0;
		for(int i=0;i<n;i++)if(c==d[i])cnt++;
		if(cnt==1)return vector<int>(0);
		int D=99999999;
		for(int i=0;i<=c;i++){
			int tmp=c-min(i,c-i);
			D=min(D,tmp);
			bool ok=false;
			for(int j=0;j<n;j++){
				if(v[j])continue;
				if(d[j]==tmp){
					v[j]=1;
					ok=true;
					e[i]=j;
					break;
				}
			}
			if(!ok)return vector<int>(0);
		}
		vector<int>ret;
		for(int i=0;i<c;i++){
			ret.push_back(e[i]);
			ret.push_back(e[i+1]);
		}
		for(int i=0;i<n;i++){
			if(v[i])continue;
			if(d[i]<=D)return vector<int>(0);
			bool ok=false;
			for(int j=0;j<=c;j++){
				if(d[e[j]]+1==d[i]){
					v[i]=1;
					ret.push_back(e[j]);
					ret.push_back(i);
					ok=true;break;
				}
			}
			if(!ok)return vector<int>(0);
		}
		return ret;
	}
<%:testing-code%>};
//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!

500:
DDCCの予選にもあった方針。

// I like wolves!!
#include <vector>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <queue>
#include <string.h>
#include <complex>
using namespace std;
const long long mod=1000000007;
class ModEquation {
	public:
	int dp[3000];
	long long dp2[52][3000];
	int to[2500][2500];
	long long pw(long long a,long long b){
		long long ret=1;
		while(b){
			if(b%2)ret=ret*a%mod;
			b/=2;
			a=a*a%mod;
		}
		return ret;
	}
	long long gcd(long long a,long long b){
		while(a){
			b%=a;swap(a,b);
		}
		return b;
	}
	vector <int> count(int n, int K, vector <int> query) {
		vector<int>y;
		for(int i=1;i*i<=K;i++){
			if(K%i==0){
				y.push_back(i);
				if(i*i<K)y.push_back(K/i);
			}
		}
		std::sort(y.begin(),y.end());
		int sz=y.size();
		for(int i=sz-1;i>=0;i--){
			dp[i]=K/y[i];
			for(int j=i+1;j<sz;j++)if(y[j]%y[i]==0)dp[i]-=dp[j];
		}
		for(int i=0;i<52;i++)for(int j=0;j<3000;j++)
			dp2[i][j]=0;
		dp2[0][0]=1;
		for(int i=0;i<sz;i++)for(int j=0;j<sz;j++){
			long long f=gcd((long long)y[i]*y[j],K);
			to[i][j]=lower_bound(y.begin(),y.end(),(int)f)-y.begin();
		//	printf("%d %d: %d\n",i,j,to[i][j]);
		}
		
		for(int i=0;i<n;i++){
			for(int j=0;j<sz;j++){
				if(!dp2[i][j])continue;
				for(int k=0;k<sz;k++){
					dp2[i+1][to[j][k]]=(dp2[i+1][to[j][k]]+dp2[i][j]*dp[k])%mod;
				}
			}
		}
		vector<int>ret;
		for(int i=0;i<query.size();i++){
			int t=lower_bound(y.begin(),y.end(),gcd(K,query[i]))-y.begin();
			long long ks=dp2[n][t];
		//	printf("%d %lld\n",t,ks);
			ks=ks*pw(dp[t],mod-2)%mod;
			ret.push_back(ks);
		}
		return ret;
	}
<%:testing-code%>};
//Powered by KawigiEdit 2.1.4 (beta) modified by pivanof!

800:
実装要素がほとんどなくて見つけたら勝ちみたいな問題だった。そういうのは大概見つけられないので詰む。

Challenge:
するメリットがなかった。

270.54 + 367.54 + 0 + 0 = 638.08 (6th)
Rating: 2489 -> 2606

事故らなければ地道に上がっていくタイプのコンテストだし、事故らなければまだまだ上がる。

Codeforces Round #381 (Div. 1)

Dが難しすぎてCがクソゲー。レッドコーダー的にはつまらないセット。

A B C D E Place
00:03 00:18 01:42 (+1) - - 51st

A:
簡単すぎて逆に焦るやつ

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int main(){
	int a,b;scanf("%d%d",&a,&b);
	int ans=9999999;
	for(int i=0;i<b;i++){
		int p,q;scanf("%d%d",&p,&q);
		ans=min(ans,q-p+1);
	}
	printf("%d\n",ans);
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%d",i%ans);
	}
	printf("\n");
}

B:
木をDFSしたときにd[深さ]=距離みたいな配列にすると、どこまでいけるか二分探索できる。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int c[210000];
vector<pair<int,int> >g[210000];
long long tmp[210000];
int par[210000];
int ans[210000];
void dfs(int a,int b){
	for(int i=0;i<g[a].size();i++){
		tmp[b+1]=tmp[b]+g[a][i].second;
		par[b+1]=g[a][i].first;
		dfs(g[a][i].first,b+1);
		ans[a]+=ans[g[a][i].first];
	}
	long long L=tmp[b]-c[a];
	int at=lower_bound(tmp,tmp+b+1,L)-tmp;
	ans[a]++;
	if(at)ans[par[at-1]]--;
}
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++)scanf("%d",c+i);
	for(int i=0;i<a-1;i++){
		int p,q;scanf("%d%d",&p,&q);
		p--;
		g[p].push_back(make_pair(i+1,q));
	}
	dfs(0,0);
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%d",ans[i]-1);
	}
	printf("\n");
}

C:
setで範囲を持って頑張って更新するだけ。何が面白いのかさっぱりわからない上、(こういう明らかに定数つきそうな問題のくせして)定数倍がきつくpretest後に落ちる。時々writerが犯す、コンテストを機械的に難しくするミスの一種。本番出てなくてよかった。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int f[310000];
long long c[310000];
int segtree[1048576];
int query(int a,int b,int c,int d,int e){
	if(d<a||b<c)return 0;
	if(c<=a&&b<=d)return segtree[e];
	return max(query(a,(a+b)/2,c,d,e*2),query((a+b)/2+1,b,c,d,e*2+1));
}
void update(int a,int b){
	a+=524288;
	segtree[a]=b;
	a/=2;
	while(a){
		segtree[a]=max(segtree[a*2],segtree[a*2+1]);
		a/=2;
	}
}
set<pair<pair<int,int>,int> >S;
set<pair<int,int> >T;
set<pair<int,int> >Tinv;
typedef set<pair<pair<int,int>,int> >::iterator wolf;
inline int sig(long long a){
	if(a<0)return -1;
	if(a==0)return 0;
	return 1;
}
int n;
void add(int a,int b){
	int sc=sig(c[a]);
	int tc=sig(c[a]+b);
	c[a]+=b;
	if(sc==tc)return;
	wolf it=S.upper_bound(make_pair(make_pair(a,mod),0));
	it--;
	pair<pair<int,int>,int> p=(*it);
	if(p.first.first<a)S.insert(make_pair(make_pair(p.first.first,a),sc));
	S.insert(make_pair(make_pair(a,a+1),tc));
	if(a+1<p.first.second)S.insert(make_pair(make_pair(a+1,p.first.second),sc));
	S.erase(p);

	wolf it2=S.upper_bound(make_pair(make_pair(p.first.first-1,mod),0));
	if(it2!=S.begin())it2--;
	if(it2!=S.begin())it2--;
	

	vector<pair<pair<int,int>,int> >que;
	vector<pair<int,int> > del2;

	for(;it2!=S.end()&&(*it2).first.first<=a+1;it2++){
		que.push_back(*it2);
	}
	int last=0;
	int len=0;
	int col=-2;
	vector<pair<pair<int,int>,int> >del;
	for(int i=0;i<que.size();i++){
		update(que[i].first.first,0);
		if(que[i].second!=col){
			if(col!=-2&&len>1){
				S.insert(make_pair(make_pair(last,que[i].first.first),col));
				for(int j=0;j<del.size();j++)S.erase(del[j]);
			}
			del.clear();
			len=0;
			last=que[i].first.first;
			col=que[i].second;
		}
		del.push_back(que[i]);
		len++;
	}
	if(len>1){
		S.insert(make_pair(make_pair(last,que[que.size()-1].first.second),col));
		for(int j=0;j<del.size();j++)S.erase(del[j]);
	}
	
	wolf it4=S.lower_bound(make_pair(make_pair(que[0].first.first,0),-mod));
	for(;it4!=S.end()&&(*it4).first.first<=a+1;it4++){
		pair<pair<int,int>,int>  d=(*it4);
		if(d.second==0)continue;
		int le=d.first.second-d.first.first;
		if(d.second==1){
			it4++;
			if(d.first.second<n-1&&(*it4).second==-1)le+=(*it4).first.second-(*it4).first.first;
			it4--;
		}
//		T.insert(make_pair(le,d.first.first));
//		Tinv.insert(make_pair(d.first.first,le));
		update(d.first.first,le);
	}
//	for(wolf i=S.begin();i!=S.end();i++)printf("%d %d: %d\n",(*i).first.first,(*i).first.second,(*i).second);
	//for(int i=0;i<n;i++)printf("%d ",segtree[524288+i]);
	//printf("\n");
}

int main(){
	int a;scanf("%d",&a);
	n=a;
	for(int i=0;i<a;i++)scanf("%d",f+i);
	if(a==1){
		int q;scanf("%d",&q);
		while(q--)printf("1\n");return 0;
	}
	for(int i=0;i<a-1;i++)c[i]=f[i+1]-f[i];
	int len=0;
	int cur=-2;
	for(int i=0;i<a-1;i++){
		int v=sig(c[i]);
		if(v!=cur){
			if(len)S.insert(make_pair(make_pair(i-len,i),cur));
			len=0;cur=v;
		}
		len++;
	}
	S.insert(make_pair(make_pair(a-1-len,a-1),cur));
	for(wolf it=S.begin();it!=S.end();it++){
		if((*it).second==0)continue;
		if((*it).second==1){
			int le=(*it).first.second-(*it).first.first;
			wolf tmp=it;
			tmp++;
			if(tmp!=S.end()&&(*tmp).second==-1)le+=(*tmp).first.second-(*tmp).first.first;
	//		T.insert(make_pair(le,(*it).first.first));
	//		Tinv.insert(make_pair((*it).first.first,le));
			update((*it).first.first,le);
		}else{
	//		T.insert(make_pair((*it).first.second-(*it).first.first,(*it).first.first));
	//		Tinv.insert(make_pair((*it).first.first,(*it).first.second-(*it).first.first));	
			update((*it).first.first,(*it).first.second-(*it).first.first);
		}
	}
	int Q;scanf("%d",&Q);
	while(Q--){
		int p,q,r;scanf("%d%d%d",&p,&q,&r);
		p--;
		if(p>=1)add(p-1,r);
		if(q<a)add(q-1,-r);
		printf("%d\n",segtree[1]+1);
	}
}

D:
時間がなくて全然考えてないけど (p,?) と (?,q) の割り当て問題? また今度。これも復元が無駄に付いてる気がするんだけど......。

Codeforces Round #382 (Div. 1)

結果もあれだがひどいセット。

A B C D E Place
00:09 (+1) 00:16 01:02 (+1) (-1) - 57th

A:
Fibonnacci heapのあの図みたいな配置。2^nではない。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int main(){
	long long a;scanf("%I64d",&a);
	int ret=0;
	while(a>1){
		ret++;a=(a+1)/2;
	}
	printf("%d\n",ret);
}

B:
ゴールドバッハから偶数の答えの最大は2。奇数は3引けば同様に最大3。あとは素数判定で場合分け。
プログラミングとは

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
bool pr(int a){
	for(int i=2;i*i<=a;i++){
		if(a%i==0)return false;
	}
	return true;
}
int main(){
	int a;scanf("%d",&a);
	if(a%2==0){
		if(a==2)printf("1\n");
		else printf("2\n");return 0;
	}
	if(pr(a))printf("1\n");
	else if(pr(a-2))printf("2\n");
	else printf("3\n");
}

C:
このセットでは珍しくプログラミング要素だが、ただ遷移が複雑でつらいだけの木DP。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int K;
long long dp[110][23][23];
vector<int>g[110];
long long dp2[110][23][23];
void calc(int a,int b){
	for(int i=0;i<g[a].size();i++){
		if(b==g[a][i])continue;
		calc(g[a][i],a);
	}
	int t=0;
	for(int i=0;i<110;i++)for(int j=0;j<23;j++)for(int k=0;k<23;k++)dp2[i][j][k]=0;
	dp2[0][K+1][1]=1;
	dp2[0][0][0]=1;
	
	for(int i=0;i<g[a].size();i++){
		if(b==g[a][i])continue;
		for(int j=0;j<=K+1;j++){
			for(int k=0;k<=K;k++){
				if(!dp2[t][j][k])continue;
				for(int l=0;l<=K+1;l++)for(int m=0;m<=K;m++){
					if(!dp[g[a][i]][l][m])continue;
					int tj=j;int tk=k;
					tj=min(tj,l+1);
					if(tj+k-1<=K)tk=0;
					if(m&&tj+m>K)tk=max(tk,m+1);
					dp2[t+1][tj][tk]=(dp2[t+1][tj][tk]+dp2[t][j][k]*dp[g[a][i]][l][m])%mod;
				}
			}
		}
		t++;
	}
	/*for(int j=0;j<=K+1;j++){
		for(int k=0;k<=K;k++){
			int tj=j;int tk=k;
			if(tj==K+1)tk++;
			dp2[t+1][tj][tk]=(dp2[t+1][tj][tk]+dp2[t][j][k])%mod;
			dp2[t+1][0][0]=(dp2[t+1][0][0]+dp2[t][j][k])%mod;
		}
	}
	t++;*/
	for(int i=0;i<=K+1;i++)for(int j=0;j<=K;j++)dp[a][i][j]=dp2[t][i][j];
//	for(int i=0;i<=K+1;i++)for(int j=0;j<=K;j++){
//		if(dp[a][i][j])printf("%d %d %d: %I64d\n",a,i,j,dp[a][i][j]);
//	}
}
int main(){
	int a,b;scanf("%d%d",&a,&b);
	K=b;
	for(int i=0;i<a-1;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		g[p].push_back(q);
		g[q].push_back(p);
	}
	calc(0,-1);
	long long ret=0;
	for(int i=0;i<=K+1;i++)ret=(ret+dp[0][i][0])%mod;
	printf("%I64d\n",ret);
}

D:
permutationの個数の偶奇は行列式の偶奇。1要素ずつ取り除いたものを転置してできる行列は余因子行列。余因子行列は、det(A)が奇数なので実質逆行列と同じ。よってビット並列で逆行列を求めるだけ。
プログラミング要素、0。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int c[2100][4100];
int s[2100];
int t[2100];
int ans[510000];
typedef unsigned long long wolf;
wolf mat[2100][65];
int D=64;
int x[510000];
int y[510000];
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);p--;q--;
		c[p][q]=1;
		x[i]=p;y[i]=q;
	}
	for(int i=0;i<a;i++)for(int j=0;j<a*2;j++){
		if(c[i][j]||j==i+a)mat[i][j/D]+=(1LL<<(j%D));
	}
	int cur=0;
	for(int i=0;i<a;i++){
		int at=-1;
		for(int j=cur;j<a;j++){
			if(mat[j][i/D]&(1LL<<(i%D))){
				at=j;break;
			}
		}
		if(!~at)continue;
		for(int k=0;k<65;k++)swap(mat[at][k],mat[cur][k]);
		for(int j=0;j<a;j++){
			if(cur==j)continue;
			if(mat[j][i/D]&(1LL<<(i%D))){
				for(int k=0;k<65;k++)mat[j][k]^=mat[cur][k];
			}
		}

		cur++;
	}
	for(int i=0;i<b;i++){
		if(mat[y[i]][(a+x[i])/D]&(1LL<<((a+x[i])%D)))printf("NO\n");
		else printf("YES\n");
	}
}

Codeforces Round #383 (Div. 1)

A B C D E Place
00:06 00:14 01:03 (+1) (-2) - 35th

悪くはないと思うんだけどね......

A:
サイクルさがしてLCM.

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int b[110];
long long gcd(long long a,long long b){
	while(a){
		b%=a;swap(a,b);
	}
	return b;
}
long long lcm(long long a,long long b){
	return a/gcd(a,b)*b;
}
int v[110];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++)scanf("%d",b+i);
	for(int i=0;i<a;i++)b[i]--;
	long long ret=1;
	for(int i=0;i<a;i++){
		if(v[i])continue;
		int at=i;
		v[at]=1;
		int cnt=0;
		while(1){
			at=b[at];
			cnt++;
			if(v[at]){
				if(at==i)break;
				else{
					printf("-1\n");return 0;
				}
			}
			v[at]=1;
		}
		if(cnt%2==0)cnt/=2;
		ret=lcm(ret,cnt);
	}
	printf("%I64d\n",ret);
}

B:
こんなやるだけ典型もういらないから

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int UF[1100];
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;
}
vector<int>v[1100];
int p[1100];
int q[1100];
int dp[1100][1100];
int main(){
	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<a;i++){
		scanf("%d",p+i);
	}
	for(int i=0;i<a;i++){
		scanf("%d",q+i);
	}
	for(int i=0;i<a;i++)UF[i]=-1;
	for(int i=0;i<b;i++){
		int s,t;scanf("%d%d",&s,&t);s--;t--;UNION(s,t);
	}
	for(int i=0;i<a;i++){
		v[FIND(i)].push_back(i);
	}
	for(int i=0;i<1100;i++)for(int j=0;j<1100;j++)dp[i][j]=-mod;
	dp[0][0]=0;
	for(int i=0;i<a;i++){
		int W=0;
		int B=0;
		for(int j=0;j<v[i].size();j++){
			W+=p[v[i][j]];
			B+=q[v[i][j]];
		}
		for(int j=0;j<=c;j++){
			dp[i+1][j]=max(dp[i+1][j],dp[i][j]);
			if(j+W<=c)dp[i+1][j+W]=max(dp[i+1][j+W],dp[i][j]+B);
			for(int k=0;k<v[i].size();k++){
				if(j+p[v[i][k]]<=c)dp[i+1][j+p[v[i][k]]]=max(dp[i+1][j+p[v[i][k]]],dp[i][j]+q[v[i][k]]);
			}
		}
	}
	int ret=0;
	for(int i=0;i<=c;i++)ret=max(ret,dp[a][i]);
	printf("%d\n",ret);
}

C:
一発ネタ。「偶数と奇数は別の色」に制約を強める(これは真に強い)と途端に簡単になる。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int UF[410000];
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 A[110000];
int B[110000];
int ans[410000];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<4*a;i++)UF[i]=-1;
	int F=a*2;
	for(int i=0;i<a;i++){
		UNION(i*2,i*2+1+F);
		UNION(i*2+F,i*2+1);
	}
	for(int i=0;i<a;i++){
		int p,q;scanf("%d%d",&p,&q);p--;q--;
		A[i]=p;B[i]=q;
		UNION(p,q+F);
		UNION(q,p+F);
	}
	for(int i=0;i<4*a;i++)ans[i]=-1;
	for(int i=0;i<a;i++){
		int f=ans[FIND(A[i])];
		if(f<0){
			ans[FIND(A[i])]=0;
			ans[FIND(A[i]+F)]=1;
			f=0;
		}
		printf("%d %d\n",f+1,(!f)+1);
	}
}

D:
dsuというCFでは頻出のアルゴリズムらしい。慣れてないアルゴリズムは実装しててもどこが悪いのかわからなくて嵌り続ける。
結局部分木のサイズを計算するのが間違っていた......

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
vector<pair<int,char> >g[510000];
char in[510000];
int ans[510000];
int dep[510000];
int sz[510000];
int key[510000];
void dfs(int a){
	sz[a]=1;
	for(int i=0;i<g[a].size();i++){
		dep[g[a][i].first]=dep[a]+1;
		key[g[a][i].first]=key[a]^(1<<(g[a][i].second-'a'));
		dfs(g[a][i].first);
		
		sz[a]+=sz[g[a][i].first];
	}
}
int wolf[1<<22];
vector<int>del;
vector<int>vis;
void dfs2(int a,int b){
	for(int i=0;i<g[a].size();i++){
		dfs2(g[a][i].first,b);
	}
	for(int k=0;k<23;k++){
		int x=key[a];
		if(k<22)x^=(1<<k);
		ans[b]=max(ans[b],dep[a]+wolf[x]-2*dep[b]);
	}
}
void dfs3(int a){
	for(int i=0;i<g[a].size();i++){
		dfs3(g[a][i].first);
	}
	if(wolf[key[a]]<0)del.push_back(key[a]);
	wolf[key[a]]=max(wolf[key[a]],dep[a]);
}
void calc(int a){
	int lc=-1;
	int val=-1;
	for(int i=0;i<g[a].size();i++){
		if(val<sz[g[a][i].first]){
			lc=g[a][i].first;
			val=sz[g[a][i].first];
		}
	}
	for(int i=0;i<g[a].size();i++){
		if(g[a][i].first==lc)continue;
		calc(g[a][i].first);
		for(int j=0;j<del.size();j++){
			wolf[del[j]]=-mod;
		}
		del.clear();
	}
	if(~lc){
		calc(lc);
		for(int i=0;i<g[a].size();i++){
			if(g[a][i].first!=lc){
				dfs2(g[a][i].first,a);
				dfs3(g[a][i].first);
			}
		}
	}
	for(int i=0;i<23;i++){
		int x=key[a];
		if(i<22)x^=(1<<i);
		ans[a]=max(ans[a],dep[a]+wolf[x]-dep[a]*2);
	}

	if(wolf[key[a]]<0)del.push_back(key[a]);
	wolf[key[a]]=max(wolf[key[a]],dep[a]);
	
	for(int i=0;i<g[a].size();i++)ans[a]=max(ans[a],ans[g[a][i].first]);
}
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a-1;i++){
		int p;
		scanf("%d%s",&p,in+i);
		p--;
		g[p].push_back(make_pair(i+1,in[i]));
	}
	dfs(0);
	for(int i=0;i<(1<<22);i++)wolf[i]=-mod;
	calc(0);
	
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%d",ans[i]);
	}
	printf("\n");
}

Codeforces Round #385 (Div. 1)

Codeforces初めまして。

A B C D E Place
00:08 00:18 00:48 - - 14th

A:
算数と変な実装。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int p[1100];
int UF[1100];
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 has[1100];
int main(){
	int a,b,c;scanf("%d%d%d",&a,&b,&c);
	for(int i=0;i<c;i++){
		scanf("%d",p+i);
		p[i]--;
	}
	for(int i=0;i<a;i++)UF[i]=-1;
	for(int i=0;i<b;i++){
		int s,t;scanf("%d%d",&s,&t);s--;t--;
		UNION(s,t);
	}
	for(int i=0;i<c;i++)has[FIND(p[i])]=1;
	int ms=0;
	int ret=-b;
	for(int i=0;i<a;i++){
		if(UF[i]<0){
			int sz=-UF[i];
			ret+=sz*(sz-1)/2;
			if(has[i]){
				ms=max(ms,sz);
			}
		}
	}
	//printf("%d\n",ret);
	for(int i=0;i<a;i++){
		if(UF[i]<0&&has[i]==0){
			ret+=ms*(-UF[i]);
			ms+=-UF[i];
		}
	}
	printf("%d\n",ret);
}

B:
i-th bitが1のもの全部/0のもの全部のを計算しておけば全部に答えられる。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int ret[1100];

int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++){
		ret[i]=mod;
	}
	for(int i=0;i<10;i++){
		vector<int>v;
		for(int j=0;j<a;j++)if(j&(1<<i)){
			v.push_back(j);
		}
		if(v.size()){
			printf("%d\n",(int)v.size());
			for(int j=0;j<v.size();j++){
				if(j)printf(" ");
				printf("%d",v[j]+1);
			}
			printf("\n");fflush(stdout);
			for(int j=0;j<a;j++){
				int f;scanf("%d",&f);
				if(!(j&(1<<i)))ret[j]=min(ret[j],f);
			}
		}
		v.clear();
		for(int j=0;j<a;j++)if(!(j&(1<<i))){
			v.push_back(j);
		}
		if(v.size()){
			printf("%d\n",(int)v.size());
			for(int j=0;j<v.size();j++){
				if(j)printf(" ");
				printf("%d",v[j]+1);
			}
			printf("\n");fflush(stdout);
			for(int j=0;j<a;j++){
				int f;scanf("%d",&f);
				if((j&(1<<i)))ret[j]=min(ret[j],f);
			}
		}
	}
	printf("-1\n");
	for(int i=0;i<a;i++){
		if(i)printf(" ");
		printf("%d",ret[i]);
	}
	printf("\n");fflush(stdout);
}

C:
dp[i][j]=集合i、赤でj得したときの青の得の最大値
普通に典型なのにみんな遅いし自分も遅い。

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<string.h>
#include<vector>
#include<set>
using namespace std;
const long long mod=1000000007;
const long long inf=mod*mod;
int dp[1<<16][130];
char in[20];
int p[20];
int q[20];
int main(){
	int a;scanf("%d",&a);
	for(int i=0;i<a;i++){
		scanf("%s%d%d",in+i,p+i,q+i);
	}
	for(int i=0;i<(1<<a);i++)for(int j=0;j<130;j++)dp[i][j]=-mod;
	dp[0][0]=0;
	int rn=0;
	for(int i=0;i<a;i++)if(in[i]=='R')rn++;
	for(int i=0;i<(1<<a);i++){
		int R=0;
		int B=0;
		for(int j=0;j<a;j++){
			if(i&(1<<j)){
				if(in[j]=='R')R++;
				else B++;
			}
		}
//		printf("%d: %d %d\n",i,R,B);
		for(int j=0;j<130;j++){
			if(dp[i][j]<0)continue;
			//printf("%d %d: %d\n",i,j,dp[i][j]);
			for(int k=0;k<a;k++){
				if(i&(1<<k))continue;
				dp[i+(1<<k)][j+min(R,p[k])]=max(dp[i+(1<<k)][j+min(R,p[k])],dp[i][j]+min(B,q[k]));
			}
		}
	}
	int rsum=0;
	int bsum=0;
	for(int i=0;i<a;i++){
		rsum+=p[i];
		bsum+=q[i];
	}
	int ret=mod*2;
	for(int i=0;i<130;i++)ret=min(ret,max(rsum-i,bsum-dp[(1<<a)-1][i]));
	printf("%d\n",ret+a);
}

D:
O(N^2 log N log ans)の解は有名だが間に合わなさげ。
反転を使うらしい。また今度。

レッドコーダーからtarget/LGMには3ヶ月でなれるか?

https://t.co/zV5iCKXjge
こんなものが最近話題になっている。

https://www.amazon.co.jp/dp/B01J9QIGF6/
あとこんなのも最近話題になっている。

そろそろ何もやってない気持ちでいっぱいになってきたし、競技プログラミングでこれを実証するのもいいんじゃないかと思ったので、試しにやってみようと思う。

続きを読む