今天又挂了TAT。
得分情况
score
watchdogs AAWWWWWWWW
planetcup AAATTTTTTT
v AAAAAAAAAA
avenger ATTTTTTTTT
题目在此,希望这个网址不要挂。
watchdogs
大水题,不过读入时错了。TAT。第一题又挂了QAQ。什么时候才能让我A掉第一题送分题?!
planetcup
非常非常水的一道题目,但是我不会做(囧),没有想到可以枚举分界线,只要想到这个就不难了。
我觉得这题的风格非常像rng_58
出的神题。Orz。他出的题往往做法看起来很简单,不过就是想不出来。
做法:枚举第一轮的第(K)名选手,然后DP即可。
v
大水题。只要知道如何合并路径的信息就非常水了。
不过听说他们每个结点要记很多东西,l神z犇h
听说记了(12)个Orz。
我记了:
- 路径长度
- 左下
- 右下
- 左上下
- 右上下
- 目前最优答案
avenger
没时间做。直接暴力(10)分。z神h犇x
Orz。
补充一下解法:
其实这题有很多特殊性,如果我们尝试着去模拟一下小数据,发现序列是有一定的规律的!
不妨把题目中所说的“在(K)进制的表示下的最低位都会出现循环变换”表示为操作change。
那么题目的伪代码就可以写成
while X > 0
p = stack.pop
change
if p <= L
repeat K times
stack.push(AK + p)
else
decrease X
令(L=cAK+d),其中(c=lfloor frac {L} {AK}
floor), (d= L mod (AK))
首先,
必须要发现的一点是:栈里的元素(i)只可能是——令(i=pAK+q),其中(0leq pleq c+1,0 leq q leq d)。
然后:
如果栈顶的元素是(p),栈顶指针为(top),
设(f(p))为(top)变为(top-1)需要change的次数。
那么对于任意的(p),有(f(p) mod K = 1)。
接着:
凭着上面所说的两点,我们可以很(ping)形(gan)象(jue)地画出一个表格:
不妨举个例子(K = 5, L = 21, A = 2),
结合表格,注意观察(X=1,2,3,4,...)时的答案(*符号是为了方便找规律):
30 31 32 33 34 * 31 32 33 34 30 * 22 23 24 *
31 32 33 34 30 * 22 23 24 * 30 31 32 33 34 *
22 23 24 * 30 31 32 33 34 * 31 32 33 34 30 *
23 24 * 30 31 32 33 34 * 31 32 33 34 30 * 22
24 * 30 31 32 33 34 * 31 32 33 34 30 * 22 23
31 32 33 34 30 * 22 23 24 * 30 31 32 33 34 *
22 23 24 * 30 31 32 33 34 * 31 32 33 34 30 *
23 24 * 30 31 32 33 34 * 31 32 33 34 30 * 22
24 * 30 31 32 33 34 * 31 32 33 34 30 * 22 23
30 31 32 33 34 * 31 32 33 34 30 * 22 23 24 *
22 23 24 * 30 31 32 33 34 * 31 32 33 34 30 *
23 24 * 30 31 32 33 34 * 31 32 33 34 30 * 22
24 * 30 31 32 33 34 * 31 32 33 34 30 * 22 23
30 31 32 33 34 * 31 32 33 34 30 * 22 23 24 *
31 32 33 34 30 * 22 23 24 * 30 31 32 33 34 *
...
(注意每一行有((d + 1) K + (K - d - 1)))个元素。
到了这里,我也不知到应该怎样用语言来描述规律了,囧(我突然感到(zi)了(ji)语(shi)言(ge)的(da)乏(ju)力(ruo)!)。
不过凭着栈的规律变化,并且结合表格(很重要所以我说两遍),我相信你已经知道了该题的解法,这里给个结论,答案的循环节为(((d + 1) K + (K - d - 1) )K^c)。
**上面所说的是第一种情况(d < K) **
如果是第二种情况(d geq k),就简单多了,例子:不妨举个例子(K = 5, L = 25, A = 2),
我们再来结合表格(很重要所以我说三遍),注意观察(X=1,2,3,4,...)时的答案:
这里就不画了。答案的循环节为(K^{c + 2})。
那应该怎样算答案呢?这里举第一种情况的例子:
- 令(t = (d + 1) K + (K - d - 1)),把(X)拆成(a_0 + a_1 t + a_2 t K + a_3 t K^2 + a_4 t K^3 ...),那么我们可以算出答案在哪一行,通过((sum_{i=0}{a_i}) mod K)。
- 再通过(a_0)的值确定是哪一列。
情况二就更简单了。
这样就大功告成了QAQ!
贴个代码(不知道对不对)
#include <cstdio>
#include <iostream>
using namespace std;
typedef unsigned long long i64;
const i64 INF = (i64) 1e19;
i64 myPower(i64 a, i64 b) {
i64 ret = 1;
for (i64 i = 0; i < b; i ++) {
if (INF / a >= ret)
ret *= a;
else return INF;
}
return ret;
}
int main() {
freopen("avenger.in", "r", stdin);
freopen("avenger.out", "w", stdout);
int cases;
cin >> cases;
for (int i = 0; i < cases; i ++) {
i64 X, K, L, A;
cin >> X >> K >> L >> A;
i64 AK = A * K;
i64 C = L / AK;
i64 D = L - C * AK;
if (D >= K - 1) {
i64 ans = 0;
X --;
X %= myPower(K, C + 2);
for (; X; X /= K) {
ans += X % K;
}
ans = ans % K + (C + 1) * AK;
cout << ans << endl;
}
else {
i64 L = D + 1;
i64 R = K - L;
i64 ans = X % (K * L + R);
X --;
X /= K * L + R;
X %= myPower(K, C);
i64 start = 0;
for (; X; X /= K) {
start += X % K;
}
start %= K;
if (start < L)
ans += start * K;
else
ans += L * K + (start - L);
ans %= K * L + R;
if (ans == 0) ans = K * L + R;
if (ans <= K * L) {
cout << ((ans - 1) % K + (ans - 1) / K) % K + AK * (C + 1) << endl;
}
else {
cout << (L + ans - K * L - 1) + AK * C << endl;
}
}
}
return 0;
}
后
幸亏gdkoi的成绩不算进gdoi,不然很可能。。。。