cfGlobalRound24--BC补题
B-Doremy's Perfect Math Class
思路:假设答案集合,在普遍的答案集合中找到特别之处.
!!假设!!a1,a2,a3,a4就是某个集合S的答案。
a2-a1=a1,即a2=2*a1.
必然的..因为a2-a1<a2,结果又存在于S中,结果只能是a1.
a3-a2=a1 or a2 ?
假如a3-a2=a2,则a3=2*a2=4*a1.那么a3-a1=3*a1..又3*a1>a2, 3*a1<a3..意味着a2,a3之间还有不存在的数。这是和一开始的假设矛盾的
所以a3-a2=a1,才是合法的.
a4-a3=a1 or a2 or a3 ?
if--a4-a3=a3,则a4=2*a3=6*a1.那么a4-a1=5*a1..又5*a1>a3, 5*a1<a4..意味着a3,a4之间还有不存在的数。这是和一开始的假设矛盾的
if--a4-a3=a2,则a4=5*a1.那么a4-a1=4*a1..又4*a1>a3,4*a1<a4..还是意味着a3,a4,之间还有不存在的数字。这是和一开始的假设矛盾的
那么a4-a3=a1.才是合法的。那么可以发现两个相邻的数字的差值是一定的,是最小的数字a1..意味着答案是一个等差数列
因为是一个等差数列,设公差为d,那么d=a1,且更大的数必然都是a1的倍数.所以答案即是maxn/a1; 但是a1不一定是输入的最小值.
如果单纯记录数组之间的最小差值,或集合本身最小值是不行的:{3,5,7,9}-->{1,2,3,4,5,6,7,8,9}; 5-3=2,3-2=1辗转相减,出现了1.----在求gcd的时候,5%3=2,3%2=1--->5-3-2=1;
9%5=4,5%4=1--->9-5-4=1;
{5,25}-->{5,10,15,20,25}
int gcd(int a,int b){
if(b==0) return a;
return gcd(b,a%b);
}
void solve(){ //补B--数学思维
//偏门:观察样例
//cout<<__gcd(24,12);
int n,_gcd=0; cin>>n;
int maxn=INT_MIN;
for(int i=1;i<=n;i++){
int x; cin>>x;
maxn=max(maxn,x);
_gcd=gcd(_gcd,x);
}
cout<<maxn/_gcd<<endl;
}
C-Doremy's City Construction
思路:又是思维题--见代码注释
void solve(){ //补C--思维 o(nlogn)
//一个小的点x,连了一个大的点y之后,大于等于y的点都不能再连了。
//即大的点y,被小的点x连了之后,y只能去连一个比y小的值
//不妨把点输入之后排序,分为小点集和大点集。
//小点集中的数可以连大点集中的大于自身的所有数.
//如此大点集中的数就被限制了,只能连一个更小的数,即小数集中的数。
//为了好计算,边都是从小数集向大数集的,即1-4-2,是看作1->4,2->4;即都是小数集连向大数集
//枚举小数集右边界。可以发现---右边界必然是某个相同数字最右边一个,否则如果选了有相同数字但是不是最右边那个,很明显会更小--贪心
int n; cin>>n;
int arr[200005],ans=0;
for(int i=1;i<=n;i++) cin>>arr[i];
sort(arr+1,arr+n+1); //点的位置是不影响的,进行排序之后更好连线
for(int i=1;i<=n;i++){ //枚举小点集合的右边界
if(i+1<=n&&arr[i+1]==arr[i]) continue;
ans=max(ans,i*(n-i));
}
if(ans!=0) cout<<ans<<endl;
else cout<<n/2<<endl;
}