http://codeforces.com/contest/204
A. Little Elephant and Interval
给你l,r,问[l,r]区间内一个数的第一位和最后一位相等的数有多少个。
简单的数位dp,其实随便对数位恶搞一下就能过。
// Author : JayYe Created Time: 2013-11-8 15:43:42
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef __int64 ll;
ll mul[22];
int a[22];
ll solve(ll n) {
if(n <= 9) return n+1;
int len = 0;
while(n) {
a[++len] = n%10;
n /= 10;
}
ll ret = 0;
for(int i = len-1;i >= 1; i--) {
if(i == 1) ret += 10;
else ret += mul[i-2]*9;
}
ret += (a[len]-1)*mul[len-2];
for(int i = len-1;i > 1; i--) {
if(a[i] > 0)
ret += (a[i])*mul[i-2];
}
if(a[len] <= a[1]) ret++;
return ret;
}
ll get(ll n) {
ll ret = 0;
for(int i = 0;i <= n; i++) {
if(i == 0) {
ret++; continue;
}
ll cur = i;
int len = 0;
while(cur) {
a[++len] = cur%10;
cur /= 10;
}
if(a[len] == a[1]) ret++;
}
return ret;
}
int main() {
mul[0] = 1;
for(int i = 1;i <= 17; i++)
mul[i] = mul[i-1]*10;
ll l, r;
scanf("%I64d%I64d", &l ,&r);
printf("%I64d\n", solve(r) - solve(l-1));
// printf("%I64d\n", get(r) - get(l-1));
return 0;
}
B. Little Elephant and Cards
水题,比A题简单多了。。
C. Little Elephant and Furik and Rubik
给你两串字符串,长度相等都为n,现在从两个字符串中分别取出长度 x (1<=x<=n)的字串,问取出来的串对齐后对应位置字符相同的期望数为多少。 也就是说 取出长度为x的字串a和字串b,ai = bi的期望个数为多少。
思路: 首先考虑某个字符,比如说a字符,这个a字符在串1中很多位置都可能出现,在串2中也一样,假设a字符在串1中i位置有出现,在串2中j位置有出现,那么取出字串后i位置刚好和j位置对应的情况有 min(i, j)* min(n-i+1, n-j+1)种。知道两个位置可以这样子算对应情况后,如果直接枚举两个串相同字符位置的话复杂度是O(n^2)的,可以把所有情况分成三种,第一种是s1[i] = s2[i],第二种是s1[i] = s2[j] (i > j),第三种是 s1[i] = s2(j) (i < j)。对于第一种情况很好算,第二种情况的话,s1[i] = s2[j],因为i > j,所以情况数肯定是 j * (n-i+1)!所以可以直接边预处理边计算情况数,对于字符x前面可以计算出x在s2中位置i的和cnt[x],对于当前s1的字符y,ans += cnt[y]*(n-i+1)即可。复杂度就变成了O(n)了,对于第三种情况也是一样的。
// Author : JayYe Created Time: 2013-11-8 18:32:26
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 5;
char a[maxn], b[maxn];
double pre[33];
int main() {
int n;
scanf("%d", &n);
scanf("%s%s", a, b);
double ans = 0;
for(int i = 0;i < n; i++) {
ans += (double)pre[a[i]-'A']*(n-i);
pre[b[i] - 'A'] += i+1;
}
memset(pre, 0, sizeof(pre));
for(int i = 0;i < n; i++) {
ans += (double)pre[b[i]-'A']*(n-i);
pre[a[i]-'A'] += i+1;
}
for(int i = 0;i < n; i++) if(a[i] == b[i]) {
ans += (double)(i+1)*(n-i);
}
double div = 0;
for(int i = 1;i <= n; i++) div += (double)i*i;
printf("%.10lf\n", ans/div);
return 0;
}
D. Little Elephant and Retro Strings
非常不错的dp。。。
给你一个串,里面有字符B,W,X。X可以是B或者W,问有至少k个连续的B并且右边有至少k个连续的W的情况数有多少种。
思路: 因为可能有多个连续的B或者连续的W存在,所以为了避免计算重复,我就直接找最左边的至少k个连续的B和最右边的至少k个连续的W,两个中间是什么都无所谓。所以要处理出到i位置还没出现过k个连续的B的情况数no_b[i]数组,可以这样子算,首先所有情况很容易计算。如果刚好到i位置出现了k个连续的B,假设小于i的no_b数组计算正确了,因为要使得到i位置刚好出现了k个连续的B,所以 a[ i-k ]必须不能是B,然后no_b[i]要减去no_b[i-k-1]即可。对于计算W的情况也差不多,反向dp一下即可。
计算出到i位置还没出现过k个连续的B的情况数no_b[i]数组后,接下来就很简单了,正向dp然后反向dp下就可以了。
// Author : JayYe Created Time: 2013-11-9 9:36:21
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef __int64 ll;
const int maxn = 1000000 + 5;
const int mod = 1000000007;
char s[maxn];
ll no_b[maxn], no_w[maxn], tot[maxn], cnt[maxn];
int sb[maxn], sw[maxn];
int exgcd(int a, int b, int &x, int &y) {
if(!b) {
x = 1; y = 0;
return a;
}
int ret = exgcd(b, a%b, y, x);
y -= a/b*x;
return ret;
}
int inv(int a, int mod) {
int x, y, d = exgcd(a, mod, x, y);
if(x < 0) x += mod;
return x;
}
int main() {
int n, k;
scanf("%d%d", &n, &k);
scanf("%s", s + 1);
tot[n+1] = 1;
for(int i = n;i >= 1; i--) {
if(s[i] == 'X') tot[i] = tot[i+1]*2%mod;
else tot[i] = tot[i+1];
}
sb[0] = 0; s[0] = 'W';
no_b[0] = 1;
cnt[0] = 0;
for(int i = 1;i <= n; i++) {
if(s[i] == 'X') no_b[i] = no_b[i-1]*2%mod;
else no_b[i] = no_b[i-1];
if(s[i] == 'W') sb[i] = 0;
else sb[i] = sb[i-1] + 1;
cnt[i] = cnt[i-1];
if(sb[i] >= k && (i == k || s[i-k] != 'B')) {
ll cur = i == k ? 1 : no_b[i-k-1];
no_b[i] = (no_b[i] - cur)%mod;
cnt[i] = (cnt[i] + cur*tot[i+1])%mod;
}
}
no_w[n+1] = no_w[n+2] = 1;
sw[n+1] = 0; s[n+1] = 'B';
ll ans = 0;
for(int i = n;i >= 1; i--) {
if(s[i] == 'X') no_w[i] = no_w[i+1]*2%mod;
else no_w[i] = no_w[i+1];
if(s[i] == 'B') sw[i] = 0;
else sw[i] = sw[i+1] + 1;
if(sw[i] >= k && (n-i+1==k || s[i+k] != 'W')) {
ll cur = no_w[i+k+1];
no_w[i] = (no_w[i] - cur)%mod;
ans = (ans + cnt[i-1]*cur%mod*inv(tot[i], mod)%mod)%mod;
}
}
printf("%I64d\n", (ans%mod + mod)%mod);
return 0;
}