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;
}

 

posted @ 2024-04-06 10:57  osir  阅读(3)  评论(0编辑  收藏  举报