2017年南邮集训队选拔 题解

A.简单求和 POJ1844

题目大意

找出最小的 n ,使对于给定的S(0<S105)使

S=k1×1+k2×2++kn×n (ki=1,1)

成立。

思路

首先知 n 的必要条件为i=1niS n×(n+1)2S ,设 Sn=n×(n+1)2 ,将 Sn 中的若干个 ki 1 改为1后,发现 Si1,,ik=Sn2×i ,可见任意的 i 的取法使Sn减去某个偶数,再进一步,可知 Si=Sn{0,2,,2Sn} ,若使 S=Si SnSmod2=0 .
所以当我们从 n=1 (或 n=1+8×S12 ,取满足 iS 的下界,解二元一次方程得,但是开方的时间开销大于枚举)向上枚举,当 SnS SnSmod2=0 时,即为我们所求最小的的 n

代码

#include<cstdio>
int main()
{
    int S, i;
    scanf("%d",&S);
    for(i=1;;i++)
        if((i*(i+1)/2-S)>=0 && (i*(i+1)/2-S)%2==0){
            printf("%d\n",i);
            break;
        }
    return 0;
}


B.悉宇大大的问题 CodeForces707C

题目大意

输入一个整数n(1n109),若以 n 与其他两个整数m,k(1m,k1018)为边长的三条边能构成一个直角三角形,则输出 m,k ,否则输出 1

思路

易知当 n=1,2 时,无法找到满足题意的 m,k
n>2 时,由于答案可能有多种情况,那么不妨设 n<m<k ,即有 n2+m2=k2 。很容易联想到平方差公式,化为 n2=(k+m)×(km) 。寻找规律发现 (3,4,5),(5,12,13),(7,24,25), , 即当 n 为奇数时,有km=1一充要条件。故解出 m=n212,k=n2+12
由此,同样的思路,当 n 为偶数时,令km=2,解得 m=n2/41,k=n2/4+1
由于此题中 m,k 超出 int 的取值范围,所以需要用 long long int

代码
#include<cstdio>
#include<cstdio>
typedef long long ll;
int main()
{
    ll n,m,k;
    scanf("%I64d",&n);
    if(n==1 || n==2){
        printf("-1\n");
        return 0;
    }
    if(n%2){
        m=(n*n-1)/2;
        k=(n*n+1)/2;
    }
    else{
        m=n*n/4-1;
        k=n*n/4+1;
    }
    printf("%I64d %I64d\n",m,k);
    return 0;
}


C.老陶的幸福生活 HDU1273

题目大意

一个节点数为 N(0<N109) 的无向完全图,每条边只能走一次。求有多少个经过每一个点的回路。

思路

对于节点数为 N 的无向完全图,每个节点度数为N1,那么取其中 (N1)/2 作为出发的边, (N1)/2 作为返回的边。
注:对于过程的有效性,每条回路使得每个点的度数减 2 。所以整个图在第i(i=0,1,,N12)次遍历前都是联通的。

代码
#include<cstdio>
int main()
{
    int n;
    while(scanf("%d",&n),n)
        printf("%d\n",(n-1)/2);
    return 0;
}

D.小朋友吃汉堡 UVA557

题目大意

有偶数 k(k=2,4,,105) 个小朋友,通过掷硬币的方法吃各有 n=k/2 个的两种汉堡,如果结果为正,吃第一种汉堡,否则吃第二种汉堡。中途若一种被吃完则不再掷。求最后两人吃到同一种汉堡的概率。

思路

求反面——最后两人吃到不同汉堡的情况,那么除了最后一个汉堡外,都进行了一次投掷。可知选取汉堡的情况数为 2×Cn12n2 种(由于最后两个汉堡的排列是两种),而每种出现的概率相等,为 0.52n1 。那么可知最后两人吃到不同汉堡的概率为 p[n]=Cn12n2/ 22n2 。由于直接计算会超出 double 的有效范围,且计算组合数时间复杂度过大,将前后概率相除化为递推式,有 p[n+1]=p[n]×(10.5/i)
最后输出 1p[k/2] 即可。

代码
#include<cstdio>
const int MAXN=50005;
double f[MAXN];
int main()
{
    f[1]=1;
    for(int i=1;i<MAXN-1;i++)
        f[i+1]=f[i]*(1-0.5/i);
    int n,i;
    scanf("%d",&n);
    while(n--){
        scanf("%d",&i);
        printf("%.4lf\n",1-f[i/2]);
    }
    return 0;
}


E.舞台灯光问题 CodeForces738B

题目大意

在由 n×m(1n,m1000) 个方格组成的长方形中,至少有一名演员在方格上。如果在某一个方格没有演员,且在此位置放置聚光灯后,在上下左右某个朝向上有演员,那么就称这是个好位置。如果两个位置的所处方格不同或聚光灯朝向不同,则认为两个位置是不同的。求好位置的总数。

思路

考虑时间复杂度为 O(n2) 的方法。如果在一行内依次枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向左照射。同理,如果在一行内逆向枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向右照射。在列上亦是。

代码
#include<cstdio>
const int MAXN=1005;
int mat[MAXN][MAXN];
int main()
{
    int n,m,sum=0;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++)
        for(int j=0;j<m;j++)
            scanf("%d",&mat[i][j]);
    for(int i=0;i<n;i++){
        bool vl=false,vr=false; //vl=ValidLeft,vr=ValidRight
        for(int j=0;j<m;j++){
            if(mat[i][j])
                vr=true;
            else if(vr)
                sum++;
        }
        for(int j=m-1;j>=0;j--){
            if(mat[i][j])
                vl=true;
            else if(vl)
                sum++;
        }
    }
    for(int j=0;j<m;j++){
        bool vu=false,vd=false; //vu=ValidUp,vd=ValidDown
        for(int i=0;i<n;i++){
            if(mat[i][j])
                vd=true;
            else if(vd)
                sum++;
        }
        for(int i=n-1;i>=0;i--){
            if(mat[i][j])
                vu=true;
            else if(vu)
                sum++;
        }
    }
    printf("%d\n",sum);
    return 0;
}


F-Boss买披萨 CodeForces731B

题目大意

有一个长度为 n(1n2×105) 的数组 ai(0ai104) ,问能否对数组经过如下处理后,使整个数组中的数都化为0。
1. a[i] 减去任意偶数个数
2. a[i] a[i+1]

思路

考虑空间复杂度 O(1) 的方法。设置布尔变量 owned 表示上一个数是否为奇数,初始化为 false 。然后依次读入,若 ai=0 owned=true 那么是不可能实现的,直接输出并跳出。否则,若 owned=true 那么 ai 需要减 1 。考察这时的ai的奇偶性,若奇,则 owned=true ,若偶,则 owned=false
最后只需考察运行完后 owned 的值是否为 false 即可。

代码
#include<cstdio>
int main()
{
    int n,a;
    bool owned=false,flag=true;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a);
        if(!a&&owned){
            printf("NO\n");
            return 0;
        }
        if(owned)
            a--;
        if(a%2)
            owned=true;
        else
            owned=false;
    }
    if(!owned)
        printf("YES\n");
    else
        printf("NO\n");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值