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;
}
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;
}
G - Mosaic
problem
think
自己写的二维线段树,开始T是因为,把update和query都写成一个函数了,导致if过多,拆成两个就A了,
code
const int N = 810;
int n;
int a[N][N];
int mi[N<<2][N<<2];
int mx[N<<2][N<<2];
int L[N<<2];
int R[N<<2];
struct point{
int a, b;
};
void build2(int l, int r, int k, int k1){
if(L[k1] == R[k1] && l==r){
mi[k1][k] = a[L[k1]][l];
mx[k1][k] = a[L[k1]][l];
return ;
}
if(l != r){
int mid2 = (l+r) >> 1;
build2(l, mid2, k<<1, k1);
build2(mid2+1, r, k<<1|1, k1);
mi[k1][k] = min(mi[k1][k<<1], mi[k1][k<<1|1]);
mx[k1][k] = max(mx[k1][k<<1], mx[k1][k<<1|1]);
} else {
mi[k1][k] = min(mi[k1<<1][k], mi[k1<<1|1][k]);
mx[k1][k] = max(mx[k1<<1][k], mx[k1<<1|1][k]);
}
}
void build1(int l, int r, int k){
L[k] = l;
R[k] = r;
if(l != r){
int mid1 = (l+r) >> 1;
build1(l, mid1, k<<1);
build1(mid1+1, r, k<<1|1);
}
build2(1, n, 1, k);
}
point query2(int l2, int r2, int k2, int k1){
if(l2 == L[k2] && r2 == R[k2]){
point ans;
ans.a = mi[k1][k2];
ans.b = mx[k1][k2];
return ans;
}
int mid2 = (L[k2] + R[k2]) >> 1;
if(r2 <= mid2) return query2(l2, r2, k2<<1, k1);
else if(l2 > mid2) return query2(l2, r2, k2<<1|1, k1);
else{
point ans1, ans2, ans;
ans1 = query2(l2, mid2, k2<<1, k1);
ans2 = query2(mid2+1, r2, k2<<1|1, k1);
ans.a = min(ans1.a, ans2.a);
ans.b = max(ans1.b, ans2.b);
return ans;
}
}
point query1(int l1, int r1, int k1, int l2, int r2, int k2){
if(l1 == L[k1] && r1 == R[k1]) return query2(l2, r2, k2, k1);
int mid1 = (L[k1] + R[k1]) >> 1;
if(r1 <= mid1) return query1(l1, r1, k1<<1, l2, r2, k2);
else if(l1 > mid1) return query1(l1, r1, k1<<1|1, l2, r2, k2);
else{
point ans1, ans2, ans;
ans1 = query1(l1, mid1, k1<<1, l2, r2, k2);
ans2 = query1(mid1+1, r1, k1<<1|1, l2, r2, k2);
ans.a = min(ans1.a, ans2.a);
ans.b = max(ans1.b, ans2.b);
return ans;
}
}
void update2(int k1, int l2, int k2, int val){
if(l2 == L[k2] && l2 == R[k2]){
if(L[k1] == R[k1]){
mi[k1][k2] = val;
mx[k1][k2] = val;
} else {
mi[k1][k2] = min(mi[k1<<1][k2], mi[k1<<1|1][k2]);
mx[k1][k2] = max(mx[k1<<1][k2], mx[k1<<1|1][k2]);
}
return ;
}
int mid2 = (L[k2] + R[k2]) >> 1;
if(l2 <= mid2) update2(k1, l2, k2<<1, val);
else update2(k1, l2, k2<<1|1, val);
mi[k1][k2] = min(mi[k1][k2<<1], mi[k1][k2<<1|1]);
mx[k1][k2] = max(mx[k1][k2<<1], mx[k1][k2<<1|1]);
}
void update1(int l1, int k1, int l2, int k2, int val){
if(l1 == L[k1] && l1 == R[k1]){
update2(k1, l2, k2, val);
return ;
}
int mid1 = (L[k1] + R[k1]) >> 1;
if(l1 <= mid1) update1(l1, k1<<1, l2, k2, val);
else update1(l1, k1<<1|1, l2, k2, val);
update2(k1, l2, k2, val);
}
int main(){
int T, tt = 0, m;
scanf("%d", &T);
while(T--){
scanf("%d", &n);
for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) scanf("%d", &a[i][j]);
build1(1, n, 1);
scanf("%d", &m);
printf("Case #%d:\n", ++tt);
while(m--){
int x, y, d;
scanf("%d%d%d", &x, &y, &d);
d /= 2;
int l1 = max(1, x - d);
int r1 = min(n, x + d);
int l2 = max(1, y - d);
int r2 = min(n, y + d);
point ans = query1(l1, r1, 1, l2, r2, 1);
int res = (ans.a + ans.b) >> 1;
printf("%d\n", res);
update1(x, 1, y, 1, res);
}
}
return 0;
}