1. 程式人生 > 實用技巧 >洛谷 7月月賽 Div.2 T1 可持久化動態仙人掌的直徑問題

洛谷 7月月賽 Div.2 T1 可持久化動態仙人掌的直徑問題

題目背景

眾所周知,一場考試需要一道簽到題。

題目描述

給定n , m,求有多少個正整數x,使得 xm ≤ n

輸入格式

一行兩個正整數n,m。

輸出格式

一個整數表示正整數x的個數。

輸入輸出樣例

輸入 #1 5 2 輸出 #1 2

說明/提示

對於25\%25%的資料滿足m = 1

對於50\%50%的資料滿足n106

對於100\%100%的資料滿足n , m ≤109


這是昨天洛谷月賽Div.2的T1
確實非常簽到(但就是花了好大功夫才做出來,淦)
看到題目首先聯想到的是快速冪
很快就否定了這種解法(其實我根本沒想用快速冪)
看到這個xm≤ n又準備用cmath庫的log函式做個換底來減少列舉量
但是花了將近四十五分鐘以後以失敗告終(誰知道這是個純暴力呢)
於是準備打個m == 1 的表(前25%)然後暴力列舉
於是有了以下程式碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <set>

using namespace std;

long long n, m;
long long x; long long cnt = 0; inline long long read() { long long x = 0; long long w = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = (x << 3
) + (x << 1) + c - '0'; c = getchar(); } return x * w * 1ll; } int main() { n = read(); m = read(); if(m == 1) printf("%lld", n); if(m > n) printf("1"); if(m == 2) { for(int i = 1; i <= sqrt(n) ; i++) { if(pow(i , 2) <= n) cnt++; } cout<<cnt; } if(m == 4) { for(int i = 1; i <= (sqrt(n)); i++) { if(pow(i , m) <= n) cnt++; } cout<<cnt; } if(m != 2 && m != 4){ for(int i = 1; i <= sqrt(n); i++) { if(pow(i , m) <= n) cnt++; cout<<cnt; } } /* double ans; // log(n)/m == log(x); double need = log(n) / m; for(int i = 1; i <= 1e6; i++) { ans = log(i); if(ans == need) { cout<<i; return 0; } } cout<<"No answer"; */ }
結果它就SPFA了...

我們來想想為啥
是陣列開小了麼——會RE
是遞迴次數不夠麼——扯
好像是這一段不大對
    if(m > n)
      printf("1");
於是在一臉懵逼中我把程式碼改成了下面這樣
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <set>

using namespace std;

long long n, m;
long long x;
long long cnt = 0;

inline long long read()
{
    long long x = 0;
    long long w = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-')
          w = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return x * w * 1ll;
}

int main()
{
    n = read();
    m = read();
    if(m == 1)
      printf("%lld", n - 1);
    if(m == 2)
    {
        for(int i = 1; i <= sqrt(n) ; i++)
        {
          if(pow(i , 2) <= n)
            cnt++;
        }
    cout<<cnt;
    }
    if(m == 4)
    {
        for(int i = 1; i <= (sqrt(n)); i++)
        {
            if(pow(i , m) <= n)
              cnt++;
        }
        cout<<cnt;
    }
    if(m != 2 && m != 4)
    {
      for(int i = 1; i <= sqrt(sqrt(n)); i++)
      {
          if(pow(i , m) <= n)
            cnt++;
      }
    cout<<cnt;
    }
    /*
    double ans;
    //  log(n)/m == log(x);
    double need = log(n) / m;
    for(int i = 1; i <= 1e6; i++)
    {
        ans = log(i);
        if(ans == need)
        {
            cout<<i;
            return 0;
        }
    }
    cout<<"No answer";
    */
}
用導數的思想對遞迴進行一些優化
於是我又交了一遍...

?
我直接疑天下之大惑
為啥會WA一個點?
???
於是開始一點點地排查
最後發現...
if(m == 1)
      printf("%lld", n);
就不該寫,導致跟後面(m != 2 && m != 4)判重了...
本來想騙的25居然沒拿到...

改成這樣就行辣(我也不知道109資料列舉咋過去的反正我就是過去了)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdlib>
#include <set>

using namespace std;

long long n, m;
long long x;
long long cnt = 0;

inline long long read()
{
    long long x = 0;
    long long w = 1;
    char c = getchar();
    while(c < '0' || c > '9')
    {
        if(c == '-')
          w = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9')
    {
        x = (x << 3) + (x << 1) + c - '0';
        c = getchar();
    }
    return x * w * 1ll;
}

int main()
{
    n = read();
    m = read();
    if(m == 1)
      printf("%d", n);
    if(m == 2)
    {
        for(int i = 1; i <= sqrt(n) ; i++)
        {
          if(pow(i , 2) <= n)
            cnt++;
        }
    cout<<cnt;
    }
    if(m == 4)
    {
        for(int i = 1; i <= (sqrt(n)); i++)
        {
            if(pow(i , m) <= n)
              cnt++;
        }
        cout<<cnt;
    }
    if(m != 2 && m != 4 && m != 1)
    {
      for(int i = 1; i <= sqrt(sqrt(n)); i++)
      {
          if(pow(i , m) <= n)
            cnt++;
      }
    cout<<cnt;
    }
    /*
    double ans;
    //  log(n)/m == log(x);
    double need = log(n) / m;
    for(int i = 1; i <= 1e6; i++)
    {
        ans = log(i);
        if(ans == need)
        {
            cout<<i;
            return 0;
        }
    }
    cout<<"No answer";
    */
}