洛谷 7月月賽 Div.2 T1 可持久化動態仙人掌的直徑問題
阿新 • • 發佈:2020-07-26
題目背景
眾所周知,一場考試需要一道簽到題。
題目描述
給定n , m,求有多少個正整數x,使得 xm ≤ n。
輸入格式
一行兩個正整數n,m。
輸出格式
一個整數表示正整數x的個數。
輸入輸出樣例
輸入 #1 5 2 輸出 #1 2說明/提示
對於25\%25%的資料滿足m = 1。
對於50\%50%的資料滿足n≤106。
對於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"; */ }