洛谷 P6511 [QkOI#R1] Quark and Equations 数学

在这里插入图片描述

首先要进行一些特判:

  1. m=1m=1n=1n=1m>nm>n 时,结果为 00

  2. m=nm=nm=n1m=n-1 时,结果为 11

此时 2mn22\le m\le n-2,对 i<ji<jiji\ge j 这两种情况分别进行讨论:

  1. i<ji<j 时,原式子变成

ji=m \lceil\frac{j}{i}\rceil=m

由于 ji=j1i+1\lceil\dfrac{j}{i}\rceil=\lfloor\dfrac{j-1}{i}\rfloor+1,因此上式等价于:

j1i+1=m \begin{aligned} \lfloor\dfrac{j-1}{i}\rfloor+1&=m\\ \end{aligned}

再代入 i+j=ni+j=n 得:

ni1i+1=mn1i=m(1) \begin{aligned} \lfloor\dfrac{n-i-1}{i}\rfloor+1&=m\\ \lfloor\dfrac{n-1}{i}\rfloor&=m\qquad (1)\\ \end{aligned}

因此转化为 i<ji<j 时,有多少个 ii 满足式 (1)(1)

  1. iji\ge j 时,原式子变成

ij=m1njj=m1nj=m(2) \begin{aligned} \lfloor\frac{i}{j}\rfloor&=m-1\\ \lfloor\frac{n-j}{j}\rfloor&=m-1\\ \lfloor\frac{n}{j}\rfloor&=m\qquad(2)\\ \end{aligned}

因此转化为 i>ji>j 时,有多少个 jj 满足式 (2)(2)

然后可以推出各自的范围:

i<ji<j 时:
n1i=mmn1iin1min1m 因为 i 是整数m>n1i1m+1>n1ii>n1m+1in1m+1+1 \begin{aligned} \lfloor\frac{n-1}{i}\rfloor&=m\\ m&\le\frac{n-1}{i}\\ i&\le\frac{n-1}{m}\\ i&\le\lfloor\frac{n-1}{m}\rfloor\text{ 因为 $i$ 是整数}\\ m&>\frac{n-1}{i}-1\\ m+1&>\frac{n-1}{i}\\ i&>\frac{n-1}{m+1}\\ i&\ge\lfloor\frac{n-1}{m+1}\rfloor+1\\ \end{aligned}

iji\ge j 时:

nj=mmnjjnmjnmm>nj1m+1>njj>nm+1jnm+1+1 \begin{aligned} \lfloor\frac{n}{j}\rfloor&=m\\ m&\le\frac{n}{j}\\ j&\le\frac{n}{m}\\ j&\le\lfloor\frac{n}{m}\rfloor\\ m&>\frac{n}{j}-1\\ m+1&>\frac{n}{j}\\ j&>\frac{n}{m+1}\\ j&\ge\lfloor\frac{n}{m+1}\rfloor+1\\ \end{aligned}

因此得到两个不等式组:

{in1min1m+1+1{jnmjnm+1+1 \begin{aligned} &\begin{cases} i&\le\lfloor\dfrac{n-1}{m}\rfloor\\ i&\ge\lfloor\dfrac{n-1}{m+1}\rfloor+1\\ \end{cases}\\ &\begin{cases} j&\le\lfloor\dfrac{n}{m}\rfloor\\ j&\ge\lfloor\dfrac{n}{m+1}\rfloor+1\\ \end{cases} \end{aligned}

因此最终的答案就是

n1mn1m+1+nmnm+1 \lfloor\dfrac{n-1}{m}\rfloor-\lfloor\dfrac{n-1}{m+1}\rfloor+\lfloor\dfrac{n}{m}\rfloor-\lfloor\dfrac{n}{m+1}\rfloor

代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int T;
ll n,m;
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld",&n,&m);
        ll res=0;
        if(m==1||m>n||n==1)res=0;
        else if(m==n||m==n-1)res=1;
        else res=(n-1)/m-(n-1)/(m+1)+n/m-n/(m+1);
        printf("%lld\n",res);
    }
    return 0;
}

当时我是用分块做的:

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
int T;
ll n,m;
int main(){
#ifdef WINE
    freopen("data.in","r",stdin);
#endif
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld",&n,&m);
        ll res=0;
        if(m==1||m>n||n==1)res=0;
        else if(m==n||m==n-1)res=1;
        else{
            //if(m==2&&(n%2==0))res++;
            ll k;
            ll i=(n-1)/(m+1);
            for(;i<=(n-1)/2;i=k+1){
                k=(n-1)/((n-1)/i);
                if((n-1)/i==m){
                    res+=k-i+1;
                    break;
                }
            }
            ll j=n/(m+1);
            for(;j<=(n-1)/2;j=k+1){
                k=n/(n/j);
                if(n/j==m){
                    res+=k-j+1;
                    break;
                }
            }
        }
        printf("%lld\n",res);
    }
    return 0;
}

posted @ 2020-05-04 18:37  winechord  阅读(107)  评论(0编辑  收藏  举报