B - Golden Radio Base
problem
给你一个数[1, 1e9],写出他的φ 进制。其中φ = (1+√5)/2 。
think
1<φ<2所以答案只包括0和1和小数点。在题目中给了两个重要信息。写成φ进制表示就是:
1)11 = 100
2)200 = 1001 (同理 2 = 10.01
于是就可以这样加下去了。可是1e9太大了,于是使用快速幂的思想。
code
int str[400];
int tmp[400];
int n;
void out() {
int st, ed;
for (int i = 0; i < 400; i++) if (str[i]) {
st = i;
break;
}
for (int i = 399; i >= 0; i--) if (str[i]) {
ed = i;
break;
}
for (int i = st; i <= 200; i++) printf("%d", str[i]);
if (ed > 200) {
printf(".");
for (int i = 201; i <= ed; i++) printf("%d", str[i]);
}
puts("");
}
void gao(int str[], int tmp[]) {
for (int i = 0; i < 400; i++) str[i] += tmp[i];
int k = 0;
while(k < 400) {
if (str[k] >= 2) {
str[k - 1] += 1; str[k] -= 2; str[k + 2] += 1;
k--;
}
else if (k > 0 && str[k] == 1 && str[k - 1] == 1) {
str[k] = 0; str[k - 1] = 0; str[k - 2] += 1;
k -= 2;
}
else k++;
}
}
void fi_pow(int k) {
memset(tmp, 0, sizeof(tmp)); memset(str, 0, sizeof(str));
tmp[200] = 1;
while(k) {
if (k & 1) gao(str, tmp);
gao(tmp, tmp);
k >>= 1;
}
}
int main () {
while(~scanf("%d", &n)) {
if (n == 1) {
puts("1");
continue;
}
fi_pow(n);
out();
}
return 0;
}
直接模拟
由于 2 = 10.01
所以 x = (x/2)(x%2).0(x/2)
500+ms, 上一个方法700+ms
code
int main () {
int n;
while(~scanf("%d", &n)) {
if (n == 1) {
puts("1");
continue;
}
memset(str, 0, sizeof(str));
str[200] = n;
bool flag = true;
while(flag){
flag = 0;
for(int i = 390; i > 0; --i){
if(str[i] >= 2){
str[i-1] += str[i] / 2;
str[i+2] += str[i] / 2;
str[i] %= 2;
flag = 1;
//out();
}
}
for(int i = 390; i > 0; --i){
if(i > 0 && str[i] && str[i-1]){
int tmp = min(str[i], str[i-1]);
str[i] -= tmp;
str[i-1] -= tmp;
str[i-2] += tmp;
flag = 1;
}
}
}
out();
}
return 0;
}
C - Little Tiger vs. Deep Monkey
problem
给出n个比赛。输得0分。赢得ai分。问要的至少多少分才有p的概率比另一个人多。
think
1)算出每种得分的概率。最多40*1000种得分。
2)其地推公式是:
p[i][j] += p[i-1][j] / 2; //表示输了,没得分,
p[i][j+score] += p[i-1][j] / 2; //表示赢了,得score分。
两种情况各占一半,所以都是p[i-1][j] / 2。
3)这样精度会爆。由于只有除以2,最多n次除以2,所以把1映射成(1<<n),这样用long long就可以了。
code
LL p[44][44000];
int main()
{
int T, n, sc;
double P;
scanf("%d", &T);
while(T--){
scanf("%d%lf", &n, &P);
P *= (1LL<<n);
memset(p, 0, sizeof(p));
p[0][0] = (1LL<<n);
int tmp = 0;
for(int i = 1; i <= n; ++i){
scanf("%d", &sc);
for(int j = 0; j <= tmp; ++j){
LL ttt = p[i-1][j] / 2LL;
p[i][j] += ttt;
p[i][j+sc] += ttt;
}
tmp += sc;
}
LL tt = 0;
int ans = 0;
for(int j = 0; tt < P; ++j){
tt += p[n][j];
ans = j;
}
printf("%d\n", ans);
}
return 0;
}
D - Bathysphere
problem
think
code
I - String
problem
在一个串str种,有多少子串满足这样的条件。长度为M*L,分为M节每节是挨着的L长度。每一节不完全相同。
think
哈希。
字符串的哈希为:a[i] = a[i+1] * seek + str[i] - 'a' + 1;
那么j到j+len之间的字符串的哈希值是:a[j] - a[j+L]*base[L];
然后用map。
code
const int MAXN = 111111;
const ULL seek = 31;
char str[MAXN];
int num[MAXN];
ULL a[MAXN];
ULL b[MAXN];
ULL base[MAXN];
map<ULL , int> mp;
int main(){
int M, L, N;
base[0] = 1;
for(int i = 1; i < MAXN; ++i) base[i] = base[i-1]*seek;
while(scanf("%d%d%s", &M, &L, str) != EOF){
N = strlen(str);
a[N] = 0;
for(int i = N - 1; i >= 0; --i) a[i] = a[i+1] * seek + str[i] - 'a' + 1;
int ans = 0;
for(int i = 0; i < L && i + M*L <= N; ++i){
mp.clear();
for(int j = i; j < i + M*L; j += L){
ULL tmp = a[j] - a[j+L]*base[L];
++mp[tmp];
}
if(mp.size() == M) ++ans;
for(int j = i + M*L; j + L <= N; j += L){
ULL tmp = a[j-M*L] - a[j-(M-1)*L]*base[L];
--mp[tmp];
if(mp[tmp] == 0) mp.erase(tmp);
tmp = a[j] - a[j+L]*base[L];
++mp[tmp];
if(mp.size() == M) ++ans;
}
}
printf("%d\n", ans);
}
return 0;
}