腾讯软开笔试题

小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2m整除。对于一串连续递增整数数列1, 2, 3, 4…, 每隔m个符号翻转一次, 最初符号为’-’;。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少。

输入描述:
输入包括两个整数n和m(2 <= n <= 109, 1 <= m), 并且满足n能被2m整除。

输出描述:
输出一个整数, 表示前n项和。

输入例子1:
8 2

输出例子1:
8

解题思路:n为数组长度,m为翻转长度,题目要求n%(2m)=0,数组长度为翻转长度的两倍的倍数,
举个栗子:
n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
2m长度的和为 -1-2+3+4=》(-1+3)+(4-2)=2
2
n = 6, m = 3, 数列就是: -1, -2, -3, +4,+5, +6.
2m长度的和为 -1-2 -3 +4+5 +6=》(-1+4)+(-2+5)+(-3+6)=33
n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
2m长度的和为 -1+2=》(-1+2)=1
1
所以长度为n的数组有n/(2m)=k,就有几个结果为kmm
所以长度为n的和可表示为m^2
(n/(2m)),可以简化为(mn)/2
代码:

#include<iostream>
using namespace std;
int main()
{
    long long n,m;//n为个数,m是翻转长度
    cin>>n>>m;
    cout<<(m*n)/2;
    return 0;
}

小Q有X首长度为A的不同的歌和Y首长度为B的不同的歌,现在小Q想用这些歌组成一个总长度正好为K的歌单,每首歌最多只能在歌单中出现一次,在不考虑歌单内歌曲的先后顺序的情况下,请问有多少种组成歌单的方法。

输入描述:
每个输入包含一个测试用例。
每个测试用例的第一行包含一个整数,表示歌单的总长度K(1<=K<=1000)。
接下来的一行包含四个正整数,分别表示歌的第一种长度A(A<=10)和数量X(X<=100)以及歌的第二种长度B(B<=10)和数量Y(Y<=100)。保证A不等于B。

输出描述:
输出一个整数,表示组成歌单的方法取模。因为答案可能会很大,输出对1000000007取模的结果。
示例1
输入
5
2 3 3 3
输出
9
解题思路:暴力求解法,通过率只有百分之七十,可能有边界条件未考虑到

#include<iostream>
#include<vector>
using namespace std;
long long getcombnum(int l1n, int k1, int l2n, int k2)//计算排列组合值 ,需要考虑k为0的情况
{
	long long c1, c2;//存放l1,l2排列组合结果
	long long mom = 1, son = 1;//存放分子分母
	if (k1 == 0)
		c1 = 1;
	else {
		mom = 1;
		son = 1;
        if(k1==l1n)
        {
            c1=1;
        }
        else{
            
            for (int i = 1; i <= k1; ++i, --l1n)
            {
                son *= l1n;
                mom *= i;
            }
            c1 = son / mom;
        }

	}
	if (k2 == 0)
		c2 = 1;
	else {
		mom = 1;
		son = 1;
        if(k2==l2n)
            c2=1;
        else
        {
            for (int i = 1; i <= k2; ++i, --l2n)
            {
                son *= l2n;
                mom *= i;
            }
            c2 = son / mom;
        }


	}

	return c1*c2;

}
int main()
{
	int l1, l2, suml;//分别表示歌单1、2长度,和歌单歌单总长
	int l1n, l2n;//歌单1、2数量
	long long res = 0,temp;//最终结果
	int s1, s2;//存放只用歌单1或2时需要的歌单最多个数			   //int num1,num2;
	vector<int> n1array;//存放长度为l1的歌的个数
	vector<int> n2array;//存放长度为l2的歌的个数
	cin >> suml >> l1 >> l1n >> l2 >> l2n;
    if(l1==l2||suml<1||suml>1000||l1<1||l1>10||l1n<=0||l1n>100||l2<1||l2>10||l2n<=0||l2n>100)
        return -1;
	s1 = suml / l1;
	s2 = suml / l2;
	if (s1>l1n)//取它和该长度本身数量较小的一个
		s1 = l1n;
	if (s2>l2n)
		s2 = l2n;
	for (int i = 0; i<=s1; ++i)//i,j为长度为1或2的歌的个数对
	{
		for (int j = 0; j<=s2; ++j)
		{
			if ((i*l1 + j*l2) == suml)
			{
				n1array.push_back(i);
				n2array.push_back(j);
				break;
			}

		}
	}
	int size = n1array.size();
	for (int i = 0; i<size; ++i)
	{
		temp = getcombnum(l1n, n1array[i], l2n, n2array[i]);
		res += temp;
	}
	cout << res%1000000007;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值