ABBYY-hard

このごろコンテスト続きでつかれるにゃー。

問題みる。とりあえずAみる。やるだけ。

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
int main()
{
	int num;
	scanf("%d",&num);
	vector<ll>vec;
	for(int i=0;i<num;i++)
	{
		ll zan;
		scanf("%I64d",&zan);
		vec.push_back(zan);
	}
	vector<ll>rui;
	ll now=1;
	for(int j=0;j<60;j++)
	{
		rui.push_back(now);
		now*=2;
	}
	ll ret=0;
	for(int k=0;k<num-1;k++)
	{
		int low=upper_bound(rui.begin(),rui.end(),num-k-1)-rui.begin()-1;
		ret+=vec[k];
		vec[k+rui[low]]+=vec[k];
		vec[k]=0;
		printf("%I64d\n",ret);
	}
}

Bみる。むずそう。
どうせ二重辺連結成分分解+LCAなんだろうなと思う。そんなの実装できない。後回し。(想定解っぽかった)
Cみる。やばげなデータ構造使いそうなにおい。あとまわし。
Dみる。20点だけ通してる人がやたら多い。20点とかnext_permutationするだけ。
取り合えず100点はガチで枝狩りすれば行けそう。8マスの値を決めればあとは必然的に決まるが、これは16*15*...*9くらいの計算量がかかりそうなので、愚直に枝を刈る。

コードひどすぎ。15重ループとか初めて書いた。

#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
	int num;
	vector<int>vec;
	scanf("%d",&num);
	int sum=0;
	for(int i=0;i<num*num;i++)
	{
		int zan;
		scanf("%d",&zan);
		sum+=zan;
		vec.push_back(zan);
	}
	sum/=num;
	printf("%d\n",sum);
	random_shuffle(vec.begin(),vec.end());
	if(num==1)
	{
		printf("%d\n",vec[0]);
	}
	if(num==2)
	{
		printf("%d %d\n%d %d\n",vec[0],vec[1],vec[2],vec[3]);
	}
	if(num==3)
	{
		for(;;)
		{
			if(vec[0]+vec[1]+vec[2]==sum&&vec[3]+vec[4]+vec[5]==sum&&vec[0]+vec[3]+vec[6]==sum&&vec[1]+vec[4]+vec[7]==sum&&vec[0]+vec[4]+vec[8]==sum&&vec[2]+vec[4]+vec[6]==sum)
			{
				printf("%d %d %d\n%d %d %d\n%d %d %d\n",vec[0],vec[1],vec[2],vec[3],vec[4],vec[5],vec[6],vec[7],vec[8]);
				break;
			}
			next_permutation(vec.begin(),vec.end());
		}
	}
	if(num==4)
	{
		for(int j=0;j<16;j++)
		{
			for(int k=0;k<16;k++)
			{
				if(j==k)
				{
					continue;
				}
				for(int l=0;l<16;l++)
				{
					if(j==l||k==l)
					{
						continue;
					}
					for(int m=0;m<16;m++)
					{
						if(j==m||k==m||l==m)
						{
							continue;
						}
						if(vec[j]+vec[k]+vec[l]+vec[m]!=sum)
						{
							continue;
						}
						vector<int>vec2;
						for(int aa=0;aa<16;aa++)
						{
							if(aa==j||aa==k||aa==l||aa==m)
							{
								continue;
							}
							vec2.push_back(vec[aa]);
						}
						for(int n=0;n<12;n++)
						{
							for(int o=0;o<12;o++)
							{
								if(n==o)
								{
									continue;
								}
								for(int p=0;p<12;p++)
								{
									if(n==p||o==p)
									{
										continue;
									}
									for(int q=0;q<12;q++)
									{
										if(n==q||o==q||p==q)
										{
											continue;
										}
										if(vec2[n]+vec2[o]+vec2[p]+vec2[q]!=sum)
										{
											continue;
										}
										vector<int>vec3;
										for(int aa=0;aa<12;aa++)
										{
											if(aa==n||aa==o||aa==p||aa==q)
											{
												continue;
											}
											vec3.push_back(vec2[aa]);
										}
										for(int r=0;r<8;r++)
										{
											for(int s=0;s<8;s++)
											{
												if(r==s)
												{
													continue;
												}
												if(vec[j]+vec2[n]+vec3[r]+vec3[s]!=sum)
												{
													continue;
												}
												for(int t=0;t<8;t++)
												{
													if(r==t||s==t)
													{
														continue;
													}
													if(vec[m]+vec2[p]+vec3[t]+vec3[s]!=sum)
													{
														continue;
													}
													for(int u=0;u<8;u++)
													{
														if(r==u||s==u||t==u)
														{
															continue;
														}
														if(vec[k]+vec2[o]+vec3[t]+vec3[u]!=sum)
														{
															continue;
														}
														vector<int>vec4;
														for(int aa=0;aa<8;aa++)
														{
															if(aa==r||aa==s||aa==t||aa==u)
															{
																continue;
															}
															vec4.push_back(vec3[aa]);
														}
														for(int v=0;v<4;v++)
														{
															for(int x=0;x<4;x++)
															{
																if(v==x)
																{
																	continue;
																}
																if(vec[l]+vec2[p]+vec4[v]+vec4[x]!=sum)
																{
																	continue;
																}
																for(int y=0;y<4;y++)
																{
																	if(v==y||x==y)
																	{
																		continue;
																	}
																	if(vec3[r]+vec3[t]+vec4[v]+vec4[y]!=sum)
																	{
																		continue;
																	}
																	int z=6-v-x-y;
																		if(vec[j]+vec2[o]+vec4[v]+vec4[z]==sum)
																		{
																			printf("%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n%d %d %d %d\n",vec[j],vec[k],vec[l],vec[m],vec2[n],vec2[o],vec2[p],vec2[q],vec3[r],vec3[t],vec4[v],vec4[y],vec3[s],vec3[u],vec4[x],vec4[z]);
																			goto l01;
																		}
																	
																}
															}
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}
l01:;
}

Eみる。変わった感じの問題。画像の入力をすると勘違いする。へぇ、標準入力から画像が読めるんだ〜(爆笑)
入力できないので捨てる。
Fみる。最大全域木かなとか思う。それじゃいけないことに気付く。UF書いた時間返せ。
DPかなとも思う。dp[使う区間][その区間で選ぶ数]でDPするのかなとか思ったが、何を選ぶかによって変わってきそう。実は辺をソートしておけばこれでできる、らしい。思いついてスルーしてしまっただけに痛い。
とりあえずもう解けそうな問題がないので、部分点回収に走る。
Fを2^nくらいで実装。20点。なぜvectorを2か所普通の配列に直しただけで時間が[TLE]->[170msくらい]になるの。サーバーおかしいだろ。

#include<stdio.h>
#include<string>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int map[2000][2000];
int par[2000];
int ran[2000];
int ren[2000];
void init()
{
	for(int i=0;i<2000;i++)
	{
		par[i]=i;
		ran[i]=0;
		ren[i]=1;
	}
}
int find(int a)
{
	if(par[a]==a)
	{
		return a;
	}
	else
	{
		return par[a]=find(par[a]);
	}
}
void unite(int a,int b)
{
	a=find(a);
	b=find(b);
	if(a==b)
	{
		return;
	}
	if(ran[a]>ran[b])
	{
		par[b]=a;
		ren[a]+=ren[b];
	}
	else
	{
		par[a]=b;
		ren[b]+=ren[a];
	}
	if(ran[a]==ran[b])
	{
		ran[b]++;
	}
}
int main()
{
	int num,gen;
	scanf("%d%d",&num,&gen);
	vector<string>vec;
	for(int i=0;i<num;i++)
	{
		string str;
		cin>>str;
		vec.push_back(str);
	}
	for(int j=0;j<num;j++)
	{
		for(int k=0;k<num;k++)
		{
			if(j!=k)
			{
				int ret=0;
				for(int l=0;l<min(vec[j].size(),vec[k].size());l++)
				{
					if(vec[j][l]!=vec[k][l])
					{
						break;
					}
					ret++;
				}
				map[j][k]=ret;
			}
		}
	}
	int ko=1;
	for(int l=0;l<num;l++)
	{
		ko*=2;
	}
	int maxi=0;
	for(int m=0;m<ko;m++)
	{
		int bit[20];
		int mon=m;
		int kos=0;
		int zan[20];
		for(int n=0;n<num;n++)
		{
			bit[n]=mon%2;
			if(mon%2==1)
			{
				zan[kos]=n;
				kos++;
			}
			mon/=2;
		}
		if(kos!=gen)
		{
			continue;
		}
		int sum=0;
		for(int o=0;o<gen;o++)
		{
			for(int p=0;p<gen;p++)
			{
				sum+=map[zan[o]][zan[p]];
			}
		}
		maxi=max(maxi,sum);
	}
	printf("%d\n",maxi/2);
}

UF書いてあるのは名残。20点獲得。

Cの部分点をとりに行く。愚直にシュミレーション。20点。

#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
	int hash,plu,query;
	scanf("%d%d%d",&hash,&plu,&query);
	int map[5000];
	fill(map,map+5000,0);
	int ret=0;
	for(int i=0;i<query;i++)
	{
		char zc;
		int ha;
		scanf(" %c%d",&zc,&ha);
		if(zc=='+')
		{
			int num;
			scanf("%d",&num);
			for(;;)
			{
				if(map[num]==0)
				{
					map[num]=ha;
					break;
				}
				ret++;
				num=(num+plu)%hash;
			}
		}
		else
		{
			for(int j=0;j<hash;j++)
			{
				if(map[j]==ha)
				{
					map[j]=0;
					break;
				}
			}
		}
	}
	printf("%d\n",ret);
}

Bの部分点をとりに行く、、、って、部分点もわからなくなった。
すべての辺を1こずつつぶしていって、その都度連結判定すればいいのか→さっきFで書いたUFが活躍。
とりあえずこれでO(E^2Qalpha(E))で20点取れる。
クエリ先読みしちゃえばO(E^2alpha(E)+EQ)でいける。50点。

#include<stdio.h>
#include<queue>
#include<algorithm>
#include<vector>
using namespace std;
int par[2000];
int ran[2000];
void init()
{
	for(int i=0;i<2000;i++)
	{
		par[i]=i;
		ran[i]=0;
	}
}
int find(int a)
{
	if(par[a]==a)
	{
		return a;
	}
	else
	{
		return par[a]=find(par[a]);
	}
}
void unite(int a,int b)
{
	a=find(a);
	b=find(b);
	if(a==b)
	{
		return;
	}
	if(ran[a]>ran[b])
	{
		par[b]=a;
	}
	else
	{
		par[a]=b;
	}
	if(ran[a]==ran[b])
	{
		ran[b]++;
	}
}
int main()
{
	int cit,way;
	scanf("%d%d",&cit,&way);
	vector<pair<int,int> >road;
	for(int j=0;j<way;j++)
	{
		int za,zb;
		scanf("%d%d",&za,&zb);
		za--;
		zb--;
		road.push_back(make_pair(za,zb));
	}
	int query;
	scanf("%d",&query);
	vector<pair<int,int> >que;
	vector<int>ans;
	for(int k=0;k<query;k++)
	{
		int za,zb;
		scanf("%d%d",&za,&zb);
		za--;
		zb--;
		que.push_back(make_pair(za,zb));
		ans.push_back(0);
	}
	for(int l=0;l<way;l++)
	{
		init();
		for(int m=0;m<way;m++)
		{
			if(l!=m)
			{
				unite(road[m].first,road[m].second);
			}
		}
		for(int n=0;n<query;n++)
		{
			if(find(que[n].first)!=find(que[n].second))
			{
				ans[n]++;
			}
		}
	}
	for(int o=0;o<query;o++)
	{
		printf("%d\n",ans[o]);
	}
}

各辺をつぶす場合に対して、だいたい同じUFをしてるから、なんか頑張ればうまくいきそうとか思ったけど、よくわからなかった。永続UFとかかな。


結果290点(ひどすぎ)

なのにratingは微増。このレートだとよほどのことをしなければ下がらないみたいだ。
rating:1779->1793(+14)rank:155