Codeforces Round #382 (Div. 2)解題報告

A.Ostap and Grasshopper

大力模擬題,然而lc233大佬居然tmd懷疑是不是一個環。。。哎想多了

題意都懶得講了orz

B.Urbanization

題意:給你n個數字,讓你選n1個數字放到A集合,n2個數字放到B集合,讓兩個集合各自的平均數  加起來最大

我們強制要求n1<n2

一個數字t放入A堆答案的貢獻是t/n1,所以排一遍序後,前n1個數字放入A集合

同理n1+1~n1+n2個數字放入B集合

大力算一發即可

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
inline void read(int &tx){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  tx=x*f; }
inline void write(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){write(x);puts("");}
using namespace std;
int n,n1,n2,a[400001];
double ans;
inline bool cmp(int x,int y){return x>y;}
int main()
{
	scanf("%d%d%d",&n,&n1,&n2);
	if(n1>n2)	swap(n1,n2);
	For(i,1,n)	scanf("%d",&a[i]);
	sort(a+1,a+n+1,cmp);
	For(i,1,n1)	ans+=(double)a[i]/n1;
	For(i,n1+1,n1+n2)	ans+=(double)a[i]/n2;
	printf("%.8lf",ans);
}
     

C.Tennis Championship

題意:n個人參加比賽,要求除第一次以外每次比賽的雙方參加比賽次數不同,問至少多少次能得出冠軍

既然要最少,那麼在場的所有人蔘加比賽次數相差不大於1。

一個顯然的結論,如果場上有x個參加t場,y個參加t-1場,則可以得到x-y個t+1場

例如5個參加t場,3個參加t-1場,則可以得到2個參加t+1場

那麼我們倒推過來

顯然就是個斐波那契啊。。。。。。

於是暴力推

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
inline void read(int &tx){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  tx=x*f; }
inline void write(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){write(x);puts("");}
using namespace std;
ll n,f[10001],tot;
int main()
{
	scanf("%lld",&n);
	f[0]=1;
	f[1]=1;
	tot=1;
	while(1)
	{
		if(f[tot]>=n)	break;
		tot++;
		f[tot]=f[tot-1]+f[tot-2];
	}
	if(f[tot]>n)	tot--;
	printf("%lld",tot-1);
}
D.Taxes

題意:給定一個n,定義f(n)爲n的最大因子(除自己),把n分成任意份,求sigma(f(ni))的最小值

lc233大佬太強了orz

當我還在懵比時,大佬直接來了一句  哥德巴赫猜想啊

????

還有這種破題????

一個不等於2的偶數,分成兩個質數,答案=2

對於一個是質數的奇數  答案=1

一個不是質數的奇數,我們分出一個2後,如果是質數了,答案=2,否則答案=3

鬼題。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(int i=j;i<=k;i++)
#define Dow(i,j,k) for(int i=k;i>=j;i--)
using namespace std;
inline void read(int &tx){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  tx=x*f; }
inline void write(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){write(x);puts("");}
using namespace std;
ll	n;

int main()
{
	scanf("%lld",&n);
	if(n==2){puts("1");return 0;}
	if(n%2==0)	{puts("2");return 0;}
	bool flag=1;
	For(i,2,sqrt(n)+1)	if(n%i==0)	flag=0;
	if(flag==1)	{puts("1");return 0;}
	n-=2;
	flag=1;
	For(i,2,sqrt(n)+1)	if(n%i==0)	flag=0;
	if(flag==1)	{puts("2");return 0;}
	puts("3");
}
     
E.Ostap and Tree

題意:給定一棵樹,可以把任意個節點標記,要求所有節點都可以以小於k的距離到達一個被標記的節點,求標記的方案數


拿到題一臉懵逼

哎,到了E題果然就是不水了啊


還是看了題解,感覺有點類似於點分的樹型dp吧

定義f[i][j]爲距離i點,最近被標記點的距離是j的方案數


聽起來很可做啊。。

對於節點x,我們每次枚舉一個son[x]

然後考慮轉移

我們要把f[son[x]][t]轉移到f[x][j]的話,相當於是在另外的son[x]中選一個位置,然後來轉移,因此是不相干的選法,顯然乘法原理


然後我們分兩類討論 

1、(t+1)+x<=2*k

那麼對於i來說,最近的被標記點爲min(t+1,x)

2、(t+1)+x>2*k

這種情況下,屬於不合法的一個狀態,因此其實我們不能認爲他是min(i+1,x),而是max(i+1,x)

這個我一開始也不是很理解,後來才發現:對於f[i][j] j>k,其實都是不合法的狀態

爲什麼要記錄呢?其實也很顯然

因爲我們轉移類似1,2*k-1這種情況時,其實是需要用到的

這樣寫可以理解爲是懶得開別的數字來存儲不合法狀態

如果不理解的話,可以畫一下圖

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#include <map>
#include <cstring>
#include <ctime>
#include <vector>
#define inf 1e9
#define ll long long
#define For(i,j,k) for(ll i=j;i<=k;i++)
#define Dow(i,j,k) for(ll i=k;i>=j;i--)
using namespace std;
inline void read(ll &tx){   ll x=0,f=1;char ch=getchar();   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}  while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  tx=x*f; }
inline void write(ll x){    if (x<0) putchar('-'),x=-x; if (x>=10) write(x/10);   putchar(x%10+'0');  }
inline void writeln(ll x){write(x);puts("");}
using namespace std;
ll mo=1e9+7;

ll poi[10001],F[10001],nxt[10001],f[1001][1001],tmp[1001],ans,n,k,x,y,cnt;
bool vis[1001];
inline void add(ll x,ll y){poi[++cnt]=y;nxt[cnt]=F[x];F[x]=cnt;}
inline void dfs(ll x)
{
	vis[x]=1;
	f[x][0]=f[x][k+1]=1;
	for(ll i=F[x];i;i=nxt[i])
	{
		ll ne=poi[i];
		if(vis[ne])	continue;
		dfs(ne);
		For(j,0,2*k+1)	tmp[j]=0;
		For(j,0,2*k+1)
			For(t,0,2*k)
			{
				if(j+t<=2*k)	
					tmp[min(j,t+1)]+=f[x][j]*f[ne][t],tmp[min(j,t+1)]%=mo;
				else
					tmp[max(j,t+1)]+=f[x][j]*f[ne][t],tmp[max(j,t+1)]%=mo;
			}
		For(j,0,2*k+1)	f[x][j]=tmp[j];
	}
}
int  main()
{
	read(n);read(k);
	For(i,1,n-1)	read(x),read(y),add(x,y),add(y,x);
	dfs(1);
	For(i,0,k)	ans+=f[1][i],ans%=mo;
	writeln(ans);
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章