BestCoder Round #85 抽屉原理/贪心/质因数

hdu 5776 sum

题意:
给一个n个数的数列,求是否存在一个连续和是m的倍数,存在输出YES。
分析:
预处理前缀和,一旦有两个数模m的值相同,说明中间一部分连续子列可以组成m的倍数。 另外,利用抽屉原理,我们可以得到,一旦n大于等于m,答案一定是YES 复杂度 O(n)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=1e5+9;
int n,m,a[N],sum[N],cnt[N];
int main()
{
    //freopen("f.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        sum[0]=0;
        memset(cnt,0,sizeof(cnt));
        bool flag=0;
        for(int i=1;i<=n;i++){
            sum[i]=sum[i-1]+a[i];
            cnt[sum[i]%m]++;
        }
        for(int i=1;i<m;i++)if(cnt[i]>1){flag=1;break;}
        if(flag||cnt[0])printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
/*
要注意一个例子:
2 3
1 2
所以要特判cnt[0]
*/

hdu 5777 domino

题意:
这里写图片描述
分析:
一共有k次机会,也就是把n个骨牌分成k段,也就是把中间的距离抹去k-1个,那就可以分成k段骨牌了。贪心,要想高度和最小,那么就要抹去最大的距离。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+9;
int n,k;
int a[N];
int main()
{
    //freopen("f.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&k);
        ll ans=0;
        for(int i=0;i<n-1;i++)scanf("%d",&a[i]),ans+=a[i];
        sort(a,a+n-1);
        int t=0;
        for(int i=n-2;i>=0&&k>=2;i--){
            ans-=a[i];
            k--;
        }
        ans+=n;
        printf("%I64d\n",ans);
    }
    return 0;
}

hdu 5778 abs

这里写图片描述

分析:
由于y质因数分解式中每个质因数均出现2次,那么y是一个完全平方数,设y=z*z,题目可转换成求z,使得每个质因数出现1次. 我们可以暴力枚举z,检查z是否符合要求,显然当z是质数是符合要求,由素数定理可以得,z的枚举量在logn级别。
因为y=x-abs或者y=x+abs,所以z在sqrt(x)左右,那么就向左向右枚举z,因为我是一遇到符合条件的z就break,因为刚开始以为这时的abs(z*z-x)就是最小的,但是忽略了一个事,就是sqrt(x)是向下取整,如果z向右枚举的时候,在遇到一个最小值之前就break了,这个其实仔细想想就明白了,WA了三次后才发现QAQ。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long ll;
bool ok(ll x)
{
    if(x<2)return false;
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            if(x%(i*i)==0)return false;
            x/=i;
        }
    }
    return true;
}
int main()
{
    //freopen("f.txt","r",stdin);
    int T;scanf("%d",&T);
    while(T--){
        ll x;
        scanf("%I64d",&x);
        ll t=sqrt(x+0.5);
        ll ans;
        while(t*t<x)t++; //这里注意
        for(ll i=t;;i++){
            if(ok(i)){
                ans=i*i-x; //y>=x
                break;
            }
        }
        for(ll i=t-1;i>0;i--)
        if(ok(i)){
            ans=min(ans,x-i*i);break; //y<=x
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

posted @ 2016-07-31 11:22  HARD_UNDERSTAND  阅读(226)  评论(0编辑  收藏  举报