BestCoder Round #71 (div.2)
Posted herongweiV
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BestCoder Round #71 (div.2)相关的知识,希望对你有一定的参考价值。
比赛链接:click here
题解:
KK‘s Steel
我们可爱的KK遇到了一道数学难题:对于一条长为N(1≤N≤10?18??)米的钢管,最多可以锯成几根小钢管,使得锯成的钢管互不相等且均不能围成三角形。
第一行一个数T(1≤T≤10),表示数据组数。
接着T行,每行一个整数N(1≤N≤10?18??),表示钢管的长度。
对于每一个数据输出一个整数,表示可以锯成的钢管数。
1
6
3
1+2+3=6 1+2=3 他们都不相同且他们不能构成三角形。
题解:已经忘记是哪一年的慈溪中学提前招生数学试卷里的题目了。
其实我们不去考虑N,我们只考虑最优切割策略:
首先肯定是尽量的小即1、2
既要不相等,又不能构成三角形,即每次为当前数列中最大的两项的和
那么,构成的数列为1,2,3,5,8,......
这样我们只要求最接近且小于等于N的Fibonacci数的项数即可。
代码:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long LLU; LLU a[1000]={1,1}; int main() { for(int i=2; i<100; ++i) a[i]=a[i-1]+a[i-2]; for(int i=2; i<100; ++i) a[i]+=a[i-1]; int t;scanf("%d",&t); while(t--) { LLU n; scanf("%I64u",&n); for(LLU i=0; i<n; ++i) { if(a[i]>n) { printf("%I64u\n",i-1); break; } } } return 0; }
KK‘s Point
我们可爱的KK遇到了一道数学难题:他在一个圆上点下了互不重合的N(2≤N≤10?5??)个点,现在他要将这N个点两两相连(圆内没有三条线交于一个点的情况),KK想知道图形中一共有多少个交点(包括边界上的点)。
第一行一个数T(1≤T≤10),表示数据组数。
接着T行,每行一个整数N(2≤N≤10?5??),表示圆上的点数。
对于每一个数据输出一个整数,表示交点数。
2
3
4
3
5
我们先撇开边界上的点不管,那么所有的点都是有两条线所构成的,手算得出N=4的时候,能形成一个点,那么,我们只要知道N个点可以构成几个四边形即可即求C(n,4),最后我们再把边界上的N个点加上, 最后的结果是C(n,4)+n;
代码:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long LLU; int main() { int t;scanf("%d",&t); while(t--) { LLU n; scanf("%I64u",&n); LLU ret=0; if(n>=4) ret=ret+n*(n-1)/2*(n-2)/3*(n-3)/4; ret+=n; printf("%I64u\n",ret); } return 0; }
KK‘s Chemical
我们可爱的KK有一道困难的化学题目:实验室有N(1≤N≤100)瓶化学药品,编号为0到N?1,现在KK知道第i瓶当且仅当和第c[i]瓶放在一起时会发生爆炸。KK得到任务要整理实验室,他需要将他们装进k个不同的盒子里。显然,为了KK的生命安全,你不能把两瓶会造成爆炸的药品放进同一个箱子。现在KK想知道有多少种不同的方案。由于答案可能会非常非常的大,所有将最后答案取10?9??+7的模即可。保证c[i]≠i。
第一行一个数T(1≤T≤200),表示数据组数。
每组数据两行,第一行两个整数N(1≤N≤100)和K(1≤K≤1000),表示化学药品的个数和需要放入的盒子数。
接下来第二行N个整数c[i](0≤c[i]≤N?1)。
对于每一个数据输出一个整数,表示方案数对10?9??+7取模后的结果。
3
3 3
1 2 0
4 3
1 2 0 0
3 2
1 2 0
6
12
0
根据药品之间的相互关系,我们可以构建一张图,我们对相互会发生反应的药品连边
这个图的特征,是一个环加上一些“树”(可能有多个联通块)
一个环(1,2,3,4,5……,n)m染色的方案数:递推,设第一个点颜色为1
f[I,1]表示i点颜色为1的种数,f[I,0]为颜色不为1时(不考虑n与1颜色不同)
则F[I,0]=f[i-1,0]*(m-2)+f[i-1,1]*(m-1),F[I,1]=f[i-1,0]
那么方案数为f[n,0]*m
一个根节点颜色固定且有k个孩子的树的m染色的方案数=(m?1)?k??,因为每个点的颜色只要与他的父亲颜色不同,即m-1种
因为乘法原理,一个联通块的方案数=环方案数*以环上每个点为根的树的积。多个联通块,再连乘即可。
KK‘s Number
我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N(1≤N≤5?10?4??)个数,每次KK都会先拿数。每次可以拿任意多个数,直到N个数被拿完。每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大。在这样的情况下,最终KK的得分减去对手的得分会是多少?
第一行一个数T(1≤T≤10),表示数据组数。
对于每组数据包含两行,第一行一个整数N(1≤N≤5?10?4??),表示个数,第二行N个正整数(不超过10?9??)。
对于每一个数据输出一个整数,表示最终KK的得分减去对手的得分。
1
3
1 3 1
2
首先KK取走3,然后对手取走两个1,那么最终分差为2。
显然,每个人的策略就是都会拿剩下的数中最大的某几个数
假如我们用f[i]表示当剩下i个数的时候先手得分-后手得分的最小值
那么得到f[i]=max(a[j+1]?f[j])(1<j≤i)
但是这样做,是要超时的
我们不妨简单转换一下 f[i]=_max; _max=max(_max,a[i+1]-f[i]);
代码:
#include <bits/stdc++.h> using namespace std; typedef unsigned long long LLU; const int maxn = 1e5+10; int a[maxn],b[maxn]; int main() { int t;t=read(); while(t--) { int n,maxx=0; n=read(); for (int i=1; i<=n; i++) a[i]=read(); sort(a+1,a+n+1); for (int i=1; i<=n; i++) maxx=max(maxx,a[i]-b[i-1]),b[i]=maxx; printf("%d\n",b[n]); } return 0; }
以上是关于BestCoder Round #71 (div.2)的主要内容,如果未能解决你的问题,请参考以下文章
BestCoder Round #69 (div.2)(hdu5611)
BestCoder Round #66 (div.2) hdu5592