首页 > 试题广场 >

翻转数列

[编程题]翻转数列
  • 热度指数:20029 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
小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

输出

8
/**
* 思路: 单纯数学规律,从第一个数字开始,每 2m 个数字之和为 m^2,总共有 n/2m 个这样的组合,因此和为 m*n/2
*/
import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        longn = sc.nextLong();
        longm = sc.nextLong();
        System.out.println(process(n, m));
    }
    public static long process(long n, long m){
        if(n % (2* m) != 0)
            return-1;
        return m * (n / 2);
    }
}

编辑于 2019-04-13 20:53:42 回复(0)
/*
解题思路:一个数列共有n/2m组,每一组的和为m^2
所以,前n项和为:(n/2m)*(m^2)=m*n/2
*/
#include <stdio.h>

int main()
{
long func(long m,long n);
long m,n,sum = 0;
scanf("%ld %ld",&m,&n);
sum = func(m,n);
printf("%ld",sum);
}
long func(long m,long n)
{
long s = 0;
s = m*n/2;
return s;
}
编辑于 2018-07-31 15:39:44 回复(0)

import sys
def reverseSum(n, m):
    a, sign, number, ans, tempSum = n // m, -1, 1, 0, 0
    for i in range(a):
        tempSum = (2*number + m - 1)*m//2
        number += m
        ans += tempSum * sign
        tempSum = 0
        sign *= -1
    return ans
 
if __name__ == "__main__":
    line = sys.stdin.readline().strip()
    values = list(map(int, line.split()))
    print(reverseSum(values[0], values[1]))

发表于 2019-09-19 11:32:45 回复(0)
因为是连续的数字所以,指定正负规律后相加的结果是有规律的,因为题目中给定的n可以被2m整除,所以正负数是成组出现的,负正负正....,根据m的变化找规律可以得到结果。
# coding=utf-8
while1:
    n,m=map(int,raw_input().split())
    #print m,n
    print(n/(2*m))*pow(m,2)
    break


发表于 2018-07-01 16:47:52 回复(2)
数学推理解答:
这道题开始就说n满足能被2m整除,所以观察得知从1开始每2m个数字和为m^2,所以n个数字有n/2m组m^2,所以有如下
#include<iostream>
using namespace std;
int main()
{
    long long n, m;
    cin >> n >> m;
   cout<<n*m/2<<endl;
     
}
编程模拟解答:
首先可以将所有的数字加起来,得出和,再从和中减去符号位为负的数字(要减的数字需要先乘上2再减掉)
#include<iostream>
using namespace std;
int main(){
	long long n,m;
	cin>>n>>m;
	long long sum = 0;
	for(int i=1;i<=n;i++){	
		sum += i;
	}
	int j = 0;//(j为组数,从零开始)
	while(m+j*m <= n){//1+j*m到m+j*m的数字为一组
		for(long long i=1+j*m;i<=m+j*m;i++)//每一轮都要从中减去一组
		sum -= 2*i;//总和相当于前n项和加上了2倍的i,所以减去2倍的i
		j+=2;//只需要减去偶数组
	}
	
	
	cout<<sum;
	
	return 0;
} 


编辑于 2021-08-10 22:39:00 回复(0)
n,m=map(int,input().split())
print(int((n*m)/2)) 

#n个数一共有n/(2m)组,而每一组求和结果为m*m。于是得到前n项和的公式:#Sn=n*m*m/(2m)=m*n/2
发表于 2021-04-03 17:38:59 回复(0)
#include <stdio.h>
int main()
{
    long long m,n;
    scanf("%lld%lld",&n,&m);
    printf("%lld\n",n/2*m);
    return 0;
}


发表于 2020-04-22 20:06:01 回复(0)
等差数列-等差数列
n,m = map(int, input().split())
print(m*n//2) # 由 (1+n)*n//2-(1+n-m)*n//2 简化得出


发表于 2019-09-24 17:17:05 回复(0)
lines=readLines("stdin")
for(l in lines){
  if(l == ""){
    break;
  }
  ll = strsplit(l, " ")[[1]]
  a=ll[1];
  b=ll[2];
  cat(as.numeric(a)*as.numeric(b)/2);
  cat('\n');
}



感觉用R的好少啊
发表于 2019-09-18 18:24:07 回复(1)
n,m = map(int,input().strip().split())
print(m**2*(n//(2*m)))

发表于 2019-09-01 12:23:02 回复(0)

import sys
 
while True:
    try:
        s = sys.stdin.readline()
        n,m = int(s.strip().split()[0]),int(s.strip().split()[1])
        print(m**2*(n//(2*m)))
    except:
        break

发表于 2019-08-31 08:33:04 回复(0)
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        
            int n=sc.nextInt(),m=sc.nextInt();
            
             long num = (long)m*n/2;
            System.out.println(num);
            
        

    }

}
注意,int*int会栈溢出,所以类型强制转换为Long 型
发表于 2019-03-17 15:18:29 回复(0)
#include<iostream>
usingnamespacestd;
 
longnumSum(doublen,doublem){
    return(double)(n/2/m)*m*m;
}
 
intmain(){
    doublen,m;
    while(cin>>n>>m){
        cout<<numSum(n,m);
    }
    return0;
}

发表于 2019-02-08 15:05:30 回复(0)
第一次做这样的题,过程曲折,光获取m、n就试了各种方式,一开始没用脑子,直接写了个循环,虽然感觉一亿次循环肯定是不对的,但是还是一根筋的先写了,想看看能够case百分之多少,后来case到了60%,估计第十次时测试用例是用了很大的数据吧,导致循环超时。附第一次的错误代码示例:
import java.util.*;
public class Main {
    public static void main(String args []) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        int m = sc.nextInt();
        // 记录正反
        boolean tag = false;
        long count = 0;
        for (long i = 1; i <= n; i++) {
            // 每 m 次反转
            if (i % m == 0) {
                tag = !tag;
            }
            if (tag) {
                count += i;
            } else {
                count -= i;
            }
        }
        System.out.println(count);
    }
}


后来再分析了一下题目,数列每经m反转,而且n必是2m的倍数,分析得出数值必是负起正收,可以切割为很多的负起正收小循环,周长为2m, 这样的循环一个有 n /(2m)个 , 小循环的步长为1,所以得出小循环中 第m + 1个数值比第 1 个 大 m ,第m +  2个比 第2 个大m, 所以每个小循环的值固定为m(反转分界值) * m (对反应次序反转后增长值)。最后结果为小循环个数 * 小循环值 n/2m * (m * m) :
import java.util.*;
public class Main {
    public static void main(String args []) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        int m = sc.nextInt();
        System.out.println((n / (m << 1)) * (m * m));
    }
}

编辑于 2019-01-07 18:09:26 回复(1)
#include<iostream>
using namespace std;
int main()
{
    int m, n;
    cin >> m;
    cin >> n;
    int sum = 0;
    if (0==n % (2 * m))
    {
        
        int a = 0;
        bool negative = true;
        for (int i = 1;i <= n;i++)
        {
            if(negative)
            {
                sum -= i;
                a++;
                if (a == m)
                {
                    a = 0;
                    negative = false;
                }
            }
            else
            {
                sum += i;
                a++;
                if (a == m)
                {
                    a = 0;
                    negative = true;
                }
            }
        }
    }
    printf("%d",sum);
    getchar();
    getchar();
    return 0;
}
发表于 2018-08-23 21:12:16 回复(0)
#include<iostream>

using namespace std;
typedef long long LL;
int main()
{
    LL n, m;
    cin >> n >> m;
   cout<<n*m/2<<endl;
     
}

发表于 2018-08-30 09:26:28 回复(0)
首先观察数列,我们可以将一组负正的数出现(如-1,-2,3,4)看作一组,则n个数一共有n/(2m)组,而每一组求和结果为m*m。于是得到前n项和的公式:Sn=n*m*m/(2m)=m*n/2
s = input()
n, m = [int(i) for i in s.split(' ')]
print((n*m)//2) 
编辑于 2021-03-20 11:26:36 回复(0)
#include<iostream>
using namespace std;
 
int main()
{
    unsigned long n,m,ret = 0;
    cin>>n>>m;
    cout<<m*n/2;
    return 0;
}

发表于 2019-12-02 23:37:33 回复(0)
import java.math.BigDecimal;
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner scan= new Scanner(System.in);
        while(scan.hasNext()){
            int num=scan.nextInt();
            int param=scan.nextInt();
            BigDecimal count=new BigDecimal(0);
            int[] array= new int[2*param];
            for (int i = 0; i <2*param; i++) {
                if(i<param){
                    array[i]=-(i+1);
                }else{
                    array[i]=i+1;
                }
                count= count.add(new BigDecimal(array[i]));
            }
            System.out.println(count.multiply(new BigDecimal(num/(2*param))));
        }
    }
}
每2m个数值加起来和一致,所以只考虑前2m个数值就可以然后乘以n/2m。

发表于 2020-03-18 14:56:07 回复(0)
果然人和人的智商是不一样的。。。。
编辑于 2024-03-17 15:49:00 回复(0)