中南林业科技大学第十一届程序设计大赛部分题解

127 篇文章 0 订阅
85 篇文章 2 订阅

C-有趣的二进制
这题注意两点。
一是因为计算机里存储整数都是补码形式,其次是负数的情况,如果是负数移位后会在最高位补1,那么就不能正确统计个数,而且程序会死循环,所以这里必须转换成usigned long long去做(变成无符号整数)。

#include <bits/stdc++.h>
using namespace std;
int  count_one_bits(unsigned long long num)
{
    int count = 0;
    while(num)
    {
        if(num&1)
        count++;
        num>>=1;
    }
    return count;
}
int main()
{
    long long n;
    while(~scanf("%lld",&n))
    {
        int cnt = count_one_bits(n);
        printf("%d\n",cnt);
    }
    return 0;
}

但是吧。。标程的操作秀蒻一脸。。。

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (long long n; cin >> n ; cout << bitset<64>(n).count() << endl) {}
    return 0;
}

G-组合数
说实话我让这名字吓到了。。
什么组合数。。。就是个贪心,用优先队列很好解决,每次取长度最短的两个,然后拼接到一起,再将其压入队列,最后size为1的时候就是答案。

#include <bits/stdc++.h>
using namespace std;

struct cmp{//定义优先级,优先长度最小的
    bool operator ()(int &a,int &b)
    {
        return a>b;
    }
};

int main()
{

    int n,x;
    while(~scanf("%d",&n))
    {
        priority_queue<int,vector<int>,cmp> q;
        for(int i = 0; i < n; ++i){
           cin>>x,q.push(x);
        }
        int ans = 0;
        while(q.size()!=1)
        {
            int s = q.top();
            q.pop();
            int b = q.top();
            q.pop();
            ans += s+b;
            q.push(s+b);
        }
        cout<<ans<<endl;
    }
    return 0;
}

I-背包问题
这道题吧。。如果你对动态规划敏感的话,看到这个n的范围就应该想到去用dfs,因为深度只和n有关,n最大只有30。

#include <bits/stdc++.h>
using namespace std;
int w[31],n,m;

int dfs(int dx,int v)
{
    if(v==0)//说明正好拿完
        return 1;
    if(v<0)//容积不够
        return 0;
    if(dx==n)
        return v>=0;//看是否容积足够
    return dfs(dx+1,v)+dfs(dx+1,v-w[dx]);//拿与不拿
}

int main()
{
    while(~scanf("%d%d",&n,&m)){
        for(int i = 0; i < n; ++i)
            scanf("%d",&w[i]);
        printf("%d\n",dfs(0,m));
    }
    return 0;
}

J-are you ok?
这道题主要就是加一这个操作,它可能会破坏序列的有序性,所以你需要维护它。。
法一:线段树(蒻不会QAQ)
但是加一只会破坏a[i-1],所以法二。
法二:stl之定义partial_sum(蒻比赛完才知道有这个东西QAQ),具体作用大家找度娘哈~~

#include <bits/stdc++.h>
const int N = 1e6+1;
using namespace std;
int a[N],Max[N];
int main()
{
    int n,q,k;
    while(~scanf("%d%d",&n,&q))
    {
        for(int i = 0; i < n; ++i){
            scanf("%d",&a[i]);
        }
        partial_sum(a,a+n,Max,[](int a,int b){ return max(a,b); });//这里是关键1
        while(q--)
        {
            scanf("%d",&k);
            int *j = lower_bound(Max,Max+n,k);
            if(j==Max+n){
                printf("are you ok\n");
            }else {
                printf("%d\n",j-Max);
            }
            if(j==Max||j==Max+n)
                continue;
            if(a[j-Max-1]==Max[j-Max-1])//关键2
                (*(j-1))++;
            a[j-Max-1]++;
        }
    }
    return 0;
}

K-序列求和
本题本意是要考大家矩阵的知识。。但是正好是有公式的,所以只需要求6的逆元就好了,这里蒻用的费马小定理。
公式推导如下:

利用恒等式(n+1)³=n³+3n²+3n+1,可以得到:
(n+1)³-n³=3n²+3n+1,
n³-(n-1)³=3(n-1)²+3(n-1)+1
.
3³-2³=3*(2²)+3*2+1
2³-1³=3*(1²)+3*1+1.
把这n个等式两端分别相加,得:
(n+1)³-1=3(1²+2²+3²+.+n²)+3(1+2+3+...+n)+n,
由于1+2+3+...+n=(n+1)n/2,
代入上式得:
n³+3n²+3n=3(1²+2²+3²+.+n²)+3(n+1)n/2+n
整理后得:
1²+2²+3²+.+n²=n(n+1)(2n+1)/6

AC代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod = 1e9+7;
ll pow_(ll a, ll n, ll p)
{
    ll ans = 1;
    ll res = a;
    while(n)
    {
        if(n&1)
            ans = ans%p*res%p;
        res = res%p*res%p;
        n >>= 1;
    }
    return ans%p;
}

//费马小定理求逆元
ll niYuan(ll a, ll b)
{
    return pow_(a,b-2,b);
}

int main()
{
    long long n;
    while(~scanf("%lld",&n))
    {
        ll ans = ((((n%mod)*((n+1)%mod))%mod*((2*n+1)%mod))%mod*niYuan(6,mod)%mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

但是如果不会求逆元,本题java大数也可过。

import java.util.*;
import java.math.*;

public class Main {

    public static void main(String[]args){
        Scanner in = new Scanner(System.in);
        BigInteger mod = new BigInteger("1000000007");
        BigInteger two = new BigInteger("2");
        BigInteger six = new BigInteger("6");
        while (in.hasNext()) {
            BigInteger n = in.nextBigInteger();
            BigInteger ans = n.multiply(n.add(BigInteger.ONE)).multiply(two.multiply(n).add(BigInteger.ONE)).divide(six).mod(mod);
            System.out.println(ans);
        }
        in.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值