开荒第一篇!SHU1981 Handsome yaoge(用余数考虑倍数问题)

Description

yaoge是一个追求完美的人,yaoge认为当他的魅力值为是M的倍数时,才是最帅气的。假设yaoge的初始魅力值为0,但他有N件增加魅力值的道具,第i件道具所能增加的魅力值为ii = 12,……,N)。现yaoge需要从中取出两件道具来增加自己的魅力值,但他又懒得计算总共有多少种方法能让自己变得最帅。希望尼萌能够帮助他。

Input

输入数据的第一行包含一个整数T,表示数据组数。

之后有T组数据,每组数据有两个整数NM

Output

对于每一组数据,输出一个整数表示满足要求的方案数。

第1 ~ 3组
1<=T<=10,1<=N,M<=1000
第4组
1<=T<=10,0<=N/M<=1000,1<=N,M<=10^9
第5组
1<=T<=1000,1<=N,M<=1000
第 6 ~ 10组
1<=T<=100000,1<=N,M<=10^9

Sample Input

4
1 3
2 3
4 3
10 10

Sample Output

0
1
2
4

这道题是校内蓝桥杯选拔的一道题,当时过了8个数据,当时用的方法如下:
#include<iostream>
#include<cstdio>
using namespace std;
int main(void)
{
    int t,n,i,minstart,k,m,len;
    long long ans;
    cin>>t;
    while(t--)
    {
        ans=0;
        scanf("%d%d",&n,&m);
        minstart=1;
        k=(n+n-1)/m;
        for(i=1;i<=k;i++)
        {
            if(minstart+n<i*m)
                minstart+=i*m-(minstart+n);
            len=i*m-minstart-minstart;
            if(len%2==0)
            {
                ans+=len/2;
            }
            else
            {
                ans+=len/2+1;
            }
        }
        cout<<ans<<endl;
         
    }
}
这个方法比起简单的暴力还是快了不少(暴力当时过了4个数据),但在校内OJ重现时还是TLE了。
于是,我重新考虑这道题,发现其实就是简单的初中数学。
思路如下:
n个数分成被m余 0~m-1堆
余数就分为 m堆
每种余数的个数是可以知道的!
那么要取两个数使其和成为m的倍数
就是在余数相加为m或者0的堆里取
k=n/m;
L=n%m;
每堆先分配k个
1-L堆是比L+1~m-1堆多1个的奇葩(划掉)
以n=11,m=5为例
余0: 5 10
余1: 1  6  11
余2: 2  7
余3: 3  8
余4: 4  9
这5堆被分为3组
{0},{1,4},{2,3}
以n=13,m=6为例
{0},{1,5},{2,4},{3}
AC的代码如下:
#include<iostream>
#include<cstdio>
using namespace std;
int main(void)
{
    long long ans;
    int t;
    long long n,m,k,L;
    cin>>t;
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        k=n/m;
        L=n%m;
        if(m%2==0)
        {
            if(L>=m/2)
                ans=(m-1-L)*k*(k+1)+(m/2-m+L)*(k+1)*(k+1)+(k+1)*k/2+(k-1)*k/2;
            else if(L==0)
                ans=k*(k-1)+(m/2-1)*k*k;
            else
                ans=k*(k-1)+L*(k+1)*k+(m/2-1-L)*k*k;
        }
        else
        {
            if(L>=m/2)
                ans=(k-1)*k/2+(m-L-1)*k*(k+1)+(m/2-m+L+1)*(k+1)*(k+1);
            else if(L==0)
                ans=k*(k-1)/2+m/2*k*k;
            else
                ans=(k-1)*k/2+L*(k+1)*k+(m/2-L)*k*k;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值