小试牛刀(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hqh131360239/article/details/82963992

思路:再来读一遍题目,就是一个取石子游戏,首先肯定第一反应就是暴力啊,暴力k值,然后直到找到满足条件的最小的k值结束,但是肯定会超时。我开始有闪过这样一个想法,都是错误的哈(只要取大于等于一半即可,妞妞取得一半是最少的,牛牛取得一半消耗的次数,然后去除,直接得到m,哈哈牛牛的每次取值是总数的1/10,不断变化的)。其实很简单k值得取值范围1~1^18,二分找到满足条件的k值啊,long long的范围为2^64,也就是对于最大的数据,64次尝试也能过。想多了,傻逼了,暴力+二分即可过。

误区:

①不低于一半,大于等于一半(n+1)/2

②1/10向下取整(直接整除即可)

③注意暴力的时候,最后一次妞妞取的时候,会出现不够取得时候。

方法一直接暴力超时;方法二暴力+二分,应该能过。

/*#include<iostream>
using namespace std;
int main(){
    long long n;
    while(cin>>n){
        long long x=(n+1)/2;
        for(long long i=1;i<=x;i++){
            long long xx=n;
            long long sum=0;
            while(xx>0){
                xx-=i;
                sum+=i;
                xx-=xx/10;
                if(sum>=x) break;
            }
            if(sum>=x) {cout<<i<<endl;break;}
        }
    }
}*/
#include<iostream>
using namespace std;
int main(){
    long long n;
    while(cin>>n){
        long long x=(n+1)/2;
        for(long long i=1;i<=x;i++){
            long long xx=n;
            long long sum=0;
            while(xx>0){
                xx-=i;
                if(xx<0) {   //不够取
                    sum+=(i+xx);
                    break;
                }else sum+=i;
                xx-=xx/10;
                if(sum>=x) break;
            }
            if(sum>=x) {cout<<i<<endl;break;}
        }
    }
}
#include<iostream>
#include<math.h>
#include<stdio.h>
using namespace std;
int main(){
    long long n;
    //freopen("1.txt","w",stdout);
    while(cin>>n){
        //n=1000000000000000000;
        long long x=(n+1)/2;
        long long l=1;
        long long r=x;
        long long ans=1000000000000000000;
        while(l<=r){
            long long i=(l+r)/2;
            long long xx=n;
            long long sum=0;
            while(xx>0){
                xx-=i;
                if(xx>=0){
                    sum+=i;
                    xx-=xx/10;
                }else{//一次拿m个,不够拿的情况
                    sum+=(i+xx);
                }
            }
            if(sum>=x) {
                //找到满足条件的了,记录最小值
                if(i<=ans){
                    ans=i;
                }
                r=i-1;
            }else{
                l=i+1;
            }
        }
        cout<<ans<<endl;
    }
    return 0;
}

思路:就是统计字母的个数,然后找取个数和为m,且个数的平方最大。策略就是先选取个数最大的,依次选择即可。

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n,m;
    string str;
    while(cin>>n>>m){
        cin>>str;
        int len=str.length();
        int a[26]={0};
        //统计每个字母的个数
        for(int i=0;i<len;i++){
            a[str[i]-65]++;
        }
        sort(a,a+26);
        //计算分数
        int sum=0;
        for(int i=25;i>=0;i--){
            if(a[i]>=m){
                sum+=m*m;
                break;
            }else{
                sum+=a[i]*a[i];
                m-=a[i];
            }
        }
        cout<<sum<<endl;
    }
    return 0;
}

思路:①把第一个数和第二个数的素数公约数全部找出来,合并,共n组数据;然后统计n组数据出现的个数,利用Map,最后遍历哪个素数的键值为n且最大,然后输出即可。

②其实两个公约数的∪集,即两个数的最小公倍数;求n个数的最大公约数。最大素数公约数一定是最大公约数的约数。如:a和b的最大公约数c,a/c和b/c之后必定没有公约数了,那么a和b的最大素数公约数必定是c的公约数。注意:最大公约数是3、5、7、11不需要操作,如果最大公约数不是素数,那么需要处理(比如:21->7)

#include <iostream>
using namespace std;
long long gcd(long long a,long long b){
    return a%b==0?b:gcd(b,a%b);
}
int main()
{
    int n;
    cin>>n;
    long long a[150005];
    long long x,y;
    for(int i=0;i<n;i++){
        cin>>x>>y;
        a[i]=x/gcd(x,y)*y;  //先除后乘,防止溢出
    }
    long long temp=a[0];
    if(temp==1){
        cout<<"-1"<<endl;
        return 0;
    }else
    for(int i=1;i<n;i++){
        temp=gcd(a[i],temp);
        if(temp==1){
            cout<<"-1"<<endl;
            return 0;
        }
    }
    //求temp的最大素数公约数
    int i;
    for(i=2;;i++){
        while(temp%i==0){   //神奇的操作
            temp/=i;
        }
        if(temp==1) break;
    }
    cout<<i<<endl;
    return 0;
}
//其实就是求最大公约数,不要被出题人迷惑了
//最大公约数,一定包含最大素数公约数
//a和b的最大公约数c,a/c和b/c之后必定没有公约数了
//那么a和b的最大素数公约数必定是c的公约数

猜你喜欢

转载自blog.csdn.net/hqh131360239/article/details/82963992