AtCoder diverta 2019 Programming Contest 2

AtCoder diverta 2019 Programming Contest 2

看起來我也不知道是一個啥比賽。 而後就寫寫題解QWQ。ios

A - Ball Distribution

有$n$個氣球$k$我的,每一個人至少要拿一個氣球。問全部分配方案中拿走氣球最多的那我的能夠比最少的那我的多拿多少個。數組

打比賽的時候一開始沒看到題,別人說輸出$n% k$就過了,而後我就過了。 如今從新一看題解。。。 應該是$k=1$時,答案是$0$,不然答案是$n-k$。ui

#include<iostream>
#include<cstdio>
using namespace std;
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int main()
{
	int n=read(),k=read();
	if(k==1)puts("0");
	else printf("%d\n",n-k);
	return 0;
}

B - Picking Up

平面上有若干個點,你能夠任意指定兩個數$p,d$。 你如今要依次選定全部點,若是在選定某個點$(x,y)$以前,存在點$(x-p,y-d)$已經被選中了,那麼代價就是$0$,不然代價是$1$。 求出選定全部點的最小代價。spa

不難想到$p,d$已是某兩個點的座標的差,那麼枚舉一下,欽定$p$爲正數,而後按照$x$從小往大排序,若是同樣就按$y$排序,依次選中就好了。若是$p=0$,就欽定$d>0$就好了。code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
using namespace std;
#define MAX 55
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n;
struct Node{int x,y;}p[MAX];
bool operator<(Node a,Node b){if(a.x!=b.x)return a.x<b.x;return a.y<b.y;}
set<Node> M;
int ans=1e9;
int main()
{
	n=read();
	for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
	if(n==1){puts("1");return 0;}
	sort(&p[1],&p[n+1]);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
		{
			int P=p[j].x-p[i].x,Q=p[j].y-p[i].y;
			if(P<0)P=-P,Q=-Q;
			M.clear();int ret=0;
			for(int k=1;k<=n;++k)
			{
				if(!M.count((Node){p[k].x-P,p[k].y-Q}))++ret;
				M.insert(p[k]);
			}
				ans=min(ans,ret);
		}
	printf("%d\n",ans);
	return 0;
}

C - Successive Subtraction

有$n$個數,執行下列操做$n-1$次:選定兩個數$a,b$,刪去它們,並把$a-b$加入進來 問最後剩下的數的最大值,而且構造一種方案。排序

首先若是咱們把操做畫成樹型結構,左兒子等價於$+1$,右兒子等價於$-1$,那麼每一個數的貢獻就是到根節點的路徑的乘積乘上自身的權值。 由於至少進行一次操做,因此至少一個數不能變號,至少一個數必須變號,其餘數任意。 因此把全部數排序以後,最大值欽定不變號,最小值欽定變號,其餘數若是是負數就變號,不然不變號。 構造方案的話,除了最大值和最小值以外,用最小值減去不變號的數,用最大值減去要變號的數,再用最大值減去最小值就好了。get

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 100100
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,a[MAX],b[MAX],s;
vector<pair<int,int> > T;
int main()
{
	n=read();
	for(int i=1;i<=n;++i)a[i]=read();
	sort(&a[1],&a[n+1]);
	for(int i=2;i<n;++i)b[i]=a[i]<0;
	b[1]=1;b[n]=0;
	for(int i=2;i<n;++i)
		if(b[i])T.push_back(make_pair(a[n],a[i])),a[n]-=a[i];
		else T.push_back(make_pair(a[1],a[i])),a[1]-=a[i];
	T.push_back(make_pair(a[n],a[1]));
	printf("%d\n",a[n]-a[1]);
	for(auto a:T)printf("%d %d\n",a.first,a.second);
	return 0;
}

D - Squirrel Merchant

你一開始有$n$塊錢,有兩家商店$A,B$。 你能夠在兩家商店把籤換成金銀銅或者把金銀銅換成錢,而且在同一家商店用錢換一單位金銀銅和一單位金銀銅換錢的錢的數量是同樣的。 如今你會先去$A$再去$B$再去$A$而後回家。 問回家後你最多有多少錢。 全部數字$\le 5000$string

首先若是隻先去$A$再去$B$,那麼作一個$dp$。設$f[i]$表示在$A$花了$i$塊錢換東西,到了$B$以後最多可以賣的錢數。 這樣子咱們就知道了到了$B$以後咱們有多少錢。 而這個錢數不會超過$N5000$,而$50005000$的數組是可以開下的,因此就再$dp$一次就作完了。it

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
#define MAX 25000100
inline ll read()
{
	ll x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
ll f[MAX],n,gA,sA,bA,gB,sB,bB;
int main()
{
	n=read();
	gA=read();sA=read();bA=read();
	gB=read();sB=read();bB=read();
	for(int i=0;i<=n;++i)
	{
		if(i+gA<=n&&gA<gB)f[i+gA]=max(f[i+gA],f[i]+gB);
		if(i+sA<=n&&sA<sB)f[i+sA]=max(f[i+sA],f[i]+sB);
		if(i+bA<=n&&bA<bB)f[i+bA]=max(f[i+bA],f[i]+bB);
	}
	ll mx=0;
	for(int i=0;i<=n;++i)mx=max(mx,f[i]-i);
	n+=mx;
	memset(f,0,sizeof(f));
	for(int i=0;i<=n;++i)
	{
		if(i+gB<=n&&gA>gB)f[i+gB]=max(f[i+gB],f[i]+gA);
		if(i+sB<=n&&sA>sB)f[i+sB]=max(f[i+sB],f[i]+sA);
		if(i+bB<=n&&bA>bB)f[i+bB]=max(f[i+bB],f[i]+bA);
	}
	mx=0;
	for(int i=0;i<=n;++i)mx=max(mx,f[i]-i);
	printf("%lld\n",mx+n);
	return 0;
}

E - Balanced Piles

有若干個數,初始時都是$0$。 加上當前的最小值爲$m$,最大值爲$M$,那麼就能夠隨意選擇一個值爲$m$的數,把它變成$[M,M+D]$中的一個任意整數。 問有多少種方法讓全部數都變成$H$。io

很妙的一道題目。 若是咱們要模擬這個過程的話,咱們須要的是最大值、最小值。即便知道了,卻也沒有辦法來計算答案,由於咱們不知道這些最小值變化以後變成了哪些數。那麼若是要模擬就必須知道全部的數。 繼續考慮,若是咱們知道最小值的個數,假設是$k$個,那麼若是要改變最小值,必定要剛好$k$次操做,此時一共有$k!$種操做方案。而變成的最大值是什麼、有多少個,顯然是能夠由咱們任意肯定的。 那麼,假如咱們知道了當前的最大值爲$M$,那麼顯然在操做以後能夠任意的把最大值變爲$[M,M+D]$中的任意一個數。同時,咱們從初始狀態開始,能夠任意的控制每次最小值的大小和個數。 那麼這就很好辦了,咱們設$f[i]$表示最大值爲$i$的方案數,它能夠轉移到$f[i+1..i+D]$,係數爲$\sum_{i=1}^n i!$,這樣子用前綴和就能夠作到$O(n)$。這樣作可行的緣由是這些最大值在以後的操做中必定會變成最小值,而且個數也不會產生變化,而這個值的個數又是能夠隨意肯定的,因此方案數剛好就是$\sum_{i=1}^n i!$。 因此答案就是$f[H]\frac{n!}{\sum_{i=1}^ni!}$,至於後面乘的係數,是由於在最小值爲$0$的時候剛好有$n$個,因此方案數是$n!$而不是$\sum_{i=1}^n i!$。

#include<iostream>
#include<cstdio>
using namespace std;
#define MOD 1000000007
#define MAX 2000200
void add(int &x,int y){x+=y;if(x>=MOD)x-=MOD;}
inline int read()
{
	int x=0;bool t=false;char ch=getchar();
	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
	if(ch=='-')t=true,ch=getchar();
	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
	return t?-x:x;
}
int n,H,D,jc[MAX],f[MAX],s[MAX];
int fpow(int a,int b){int s=1;while(b){if(b&1)s=1ll*s*a%MOD;a=1ll*a*a%MOD;b>>=1;}return s;}
int main()
{
	n=read();H=read();D=read();
	jc[0]=1;for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%MOD;
	int sj=0;for(int i=1;i<=n;++i)sj=(sj+jc[i])%MOD;
	f[0]=s[0]=1;
	for(int i=1;i<=H;++i)f[i]=1ll*sj*(s[i-1]+MOD-(i-D<=0?0:s[i-D-1]))%MOD,s[i]=(s[i-1]+f[i])%MOD;
	int ans=1ll*f[H]*jc[n]%MOD*fpow(sj,MOD-2)%MOD;
	printf("%d\n",ans);
	return 0;
}

F - Diverta City

有一張$n$個點的徹底圖,你須要肯定任意兩個點之間的邊的邊權,使得全部的、共$\frac{n!}{2}$條哈密頓迴路的邊權和都不相同。 要求全部邊權都是正數,且邊權和不超過$10^{11}$。

什麼神仙構造方法...... 考慮增量法,每次加入一個點,定義每一個點有一個權值$f_i$,其中$f={1,2,4,7,12,20,29,38,52,73}$,這個數列知足任意兩個數字都不相同、任意兩個數字的和也都不相同。 每次連邊的時候就是$i\rightarrow j(i<j)$,邊權爲$(M+1)*a_i$,其中$M$是加入這個點以前的哈密頓路長度的最大值。 至於這樣爲啥是對的。。。。 由於每次新的哈密頓迴路組成的兩條邊必定比以前的全部邊都要大,因此互相不影響,且又所有不等。。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
int n,p[11],a[11]={0,1,2,4,7,12,20,29,38,52,73};
ll g[11][11],M;
int main()
{
	scanf("%d",&n);
	for(int i=2;i<=n;++i)
	{
		for(int j=1;j<i;++j)g[i][j]=g[j][i]=(M+1)*a[j];
		if(i==n)break;
		for(int j=1;j<=i;++j)p[j]=j;
		do
		{
			ll s=0;
			for(int j=1;j<i;++j)s+=g[p[j]][p[j+1]];
			M=max(M,s);
		}while(next_permutation(&p[1],&p[i+1]));
	}
	for(int i=1;i<=n;++i,puts(""))
		for(int j=1;j<=n;++j)
			printf("%lld ",g[i][j]);
	return 0;
}
相關文章
相關標籤/搜索