[USACO09MAR]Moon Mooing
某谷的翻译挺迷的,简单来说就是给一个初值c,然后有两个函数f1 = a1 * x / d1 + b1, f2 = a2 * x / d2 + b2.把c分别带进去,所得的结果也递归带进去,这样的到一串数,输出第n小的。
这道题如果都带进去,然后在排序肯定行不通,因为这一串数不是递增的,不能确定后面多少有比当前数小的。
那或许会想到,可以用一个优先队列维护最小值,这样就避免排序啦。然而数据是4e6,O(nlogn)够强能过啊。
其实没那么难,完全可以用一个普通队列实现这个功能。首先我们建两个指针f1, f2,分别代表该函数该算序列中的哪一个数了。然后得出的x, y取最小值作为本次的答案放到末尾。因为选的是当前最小值,而且f(x) > x,所以可以保证这个队列一定是单调递增的。然后如果f1得出本次的答案,就f1++。
需要注意的是,指针向后移动不能写一个 if 然后else,因为如果两个函数计算出相同的值,应该都向后移动。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<vector> 8 #include<queue> 9 #include<stack> 10 #include<cctype> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a) memset(a, 0, sizeof(a)) 15 typedef long long ll; 16 typedef double db; 17 const int INF = 0x3f3f3f3f; 18 const db eps = 1e-8; 19 const int maxn = 4e6 + 5; 20 inline ll read() 21 { 22 ll ans = 0; 23 char ch = getchar(), last = ' '; 24 while(!isdigit(ch)) last = ch, ch = getchar(); 25 while(isdigit(ch)) ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar(); 26 if(last == '-') ans = -ans; 27 return ans; 28 } 29 inline void write(ll x) 30 { 31 if(x < 0) putchar('-'), x = -x; 32 if(x >= 10) write(x / 10); 33 putchar(x % 10 + '0'); 34 } 35 36 int c, n, a1, b1, d1, a2, b2, d2; 37 int f1 = 1, f2 = 1; 38 ll a[maxn]; 39 40 int main() 41 { 42 c = read(); n = read(); 43 a1 = read(); b1 = read(); d1 = read(); a2 = read(); b2 = read(); d2 = read(); 44 a[1] = c; 45 for(int i = 2; i <= n; ++i) 46 { 47 ull x = min(a1 * a[f1] / d1 + b1, a2 * a[f2] / d2 + b2); 48 a[i] = x; 49 if(x == a1 * a[f1] / d1 + b1) f1++; 50 if(x == a2 * a[f2] / d2 + b2) f2++; 51 } 52 write(a[n]); enter; 53 return 0; 54 }