258A - Little Elephanh and Bits
小象有一个二进制表示的整数a。现在它要删掉一个二进制位,使这个新整数最大。
输入
a(二进制形式,位数小于$10^5)
输出
新整数(二进制形式)
样例
input
101
output
11
input
110010
output
11010
题解
显然删去尽量高位的0答案就最大,当然没有0的话随便删个1就好了。
代码
#include <cstdio>
#include <cstring>
#define FOR(i,j,k) for(i=j;i<=k;++i)
const int N = 100005;
char ch[N], tmp[N], ans[N];
int main() {
int i, x = 0, j, len;
scanf("%s", ch + 1);
len = strlen(ch + 1);
FOR(i,1,len) if (ch[i] == '0' || i == len - 1) {
FOR(j,1,len) if (i != j) putchar(ch[j]);
break;
}
return 0;
}
258B - Little Elephant and Elections
动物园最近有很多选举活动。总共有7个主要的政党,其中有一个是小象政党(LEPP,Little Elephant Politicial Party),另外6个党的名字我也不知道。
获得的选票数对一个政党来说很重要,现在有
1,2,3,⋯,m
共m个数字,7个政党与这些政党有着微妙的联系。
LEPP认为4和7是他们的幸运数,他们希望估计他们在选举中的成功概率。因此,他们需要找出,有多少种LEPP能获得的选票数,其中4和7的数量严格多余剩下6个政党的选票数中4和7的个数。
请你帮助LEPP,计算选票数的方案数。模
109+7
。
输入
一行一个整数 m(7≤m≤109) ,选票的可能数量。
输出
方案数。模 109+7 。
Examples
input
7
output
0
input
8
output
1440
题解
首先,让我们考虑
ci
,表示
[1,m]
中4和7的数量等于
i
的。一个简单的数位dp:
首先,dp[i][j]
表示i位数有j个4/7的数字的个数,显然:
dp[i][j]=sum: dp[i-1][j-1]*2+dp[i-1][j]*8
然后按照数位dp的套路就可以算出
然后就可以暴力dfs找出所有的可能的6个政党的分配方法。
代码
#include <cstdio>
typedef long long ll;
const ll MOD = 1e9+7;
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
ll ANS = 0, dp[16][16], c[16];
int work(int m, int n) {
int bit[16], l = 0, cnt = 0, tot = 0, i, j;
for (; m; m /= 10) bit[++l] = m % 10;
for (i = l; i && tot <= n; --i) {
rep(j,0,bit[i])
if (j == 4 || j == 7) {
if (tot < n)
cnt += dp[i - 1][n - tot - 1];
} else
cnt += dp[i - 1][n - tot];
if (bit[i] == 4 || bit[i] == 7) ++tot;
}
if (tot == n) ++cnt;
if (n == 0) --cnt;
return cnt;
}
void dfs(int t, int now, int lim, ll ans) {
if (t == 6) (ANS += ans) %= MOD;
else {
for (int i = 0; i <= 9 && i + now < lim; ++i)
if (c[i]) {
c[i]--;
dfs(t + 1, now + i, lim, ans * (c[i] + 1) % MOD);
c[i]++;
}
}
}
int main() {
int m, i, j, k, l;
scanf("%d", &m);
dp[0][0] = 1;
FOR(i,0,9) FOR(j,0,i) {
dp[i + 1][j + 1] += dp[i][j] * 2; // 4/7
dp[i + 1][j] += dp[i][j] * 8; // 0/1/2/3/5/6/8/9
}
FOR(i,0,9) c[i] = work(m, i);
FOR(i,0,9) if (c[i]) {
--c[i];
dfs(0, 0, i, (c[i] + 1) % MOD);
++c[i];
}
printf("%I64d", ANS);
return 0;
}
258C - Little Elephant and LCM
小象很喜欢算一些正整数的lcm(最小公倍数)。
假设有一个序列
b1,b2,⋯,bn
,认为序列b是好序列,当且仅当他们的最小公倍数
lcm{b1,b2,⋯,bn}=max{b1,b2,⋯,bn}
小象还有个数列
a1,a2,⋯,an
,你的任务是帮他找到好数列
{bn}
的个数,
{bn}
满足
1≤bi≤ai(1≤i≤n)
。
输入
第一行一个正整数
n(1≤n≤105)
,表示
{an}
的元素个数。
第二行
n
个正整数
输出
一行一个整数,好数列 {bn} 的个数。模 109+7
样例
样例输入1
4
1 4 3 2
样例输出1
15
样例输入2
2
6 3
样例输出2
13
题解
关于题目的条件
lcm{bn}=max{bn}
,等价于条件:
bi
是
max{bn}=m
的因数。算出
m
的所有因数
258E - Little Elephant and Tree
小象十分喜欢树,而且它特别喜欢有根树。
它获得了一棵n个节点的树,根节点为1号,每个节点一开始都有一个空集合。
小象希望完成m个操作。第i个操作它给节点
ai
的子树中所有节点的集合都加入i,对
bi
也是这样
完成操作后它想知道每个节点i的一个数
ci
,表示有多少个节点的集合和i的集合交集不为空。
你的任务是帮它算出所有的
ci
输入
第一行2个整数
n,m(1≤n,m≤105)
,树的节点数和操作数
接下来的
n−1
行,每行2个整数
ui,vi(1≤ui,vi≤n)
,表示一条边,保证输入数据有效且是一棵树
接下来的
m
行,每行2个整数
输出
一行
n
个整数
Examples
input
5 1
1 2
1 3
3 5
3 4
2 3
output
0 3 3 3 3
input
11 3
1 2
2 3
2 4
1 5
5 6
5 7
5 8
6 9
8 10
8 11
2 9
3 6
2 8
output
0 6 7 6 0 2 0 5 4 5 5
题解
注意到每次都是处理子树,处理子树的方法有先序、线段树或树链剖分等。我们先得出树的先序序列,那么树上问题就转化为序列问题了。
比如样例2的先序序列:
1 2 3 4 5 6 9 7 8 10 11
----- -
- ---
----- -------
###############################
----- - -------
前三行-
表示操作影响到的元素。
注意到对于每个元素,它的
ci
就为所有能覆盖到i的完整操作的线段并的长度。比如经过2的操作有1、3,两个操作合并后为最后一行-
。长度=7,减去2本身就是答案6。
那么我们就需要维护线段的并,线段树显然能轻易维护。
由于我们无法做到直接利用线段树查询我们的答案,我们可以维护这样的线段树,这个线段树只包含和这个元素有关的线段,那么整个线段树的解就是答案了。
代码
#include <cstdio>
#define FOR(i,j,k) for(i=j;i<=k;++i)
#define rep(i,j,k) for(i=j;i<k;++i)
#define forEach(x,val,graph) for(int it=(graph)->h[x],val=(graph)->v[it];it;it=(graph)->p[it],val=(graph)->v[it])
int read() {
int f = 1, s = 0; char ch = getchar();
for ( ; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
for ( ; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
return s * f;
}
const int N = 100005, M = N * 2;
int n, m, p1[N], p2[N], ans[N];
struct SegTree {
int s[N * 4], num[N * 4];
void update(int t, int l, int r) {
if (s[t]) num[t] = r - l + 1;
else if (l == r) num[t] = 0;
else num[t] = num[t * 2] + num[t * 2 + 1];
}
void add(int t, int l, int r, int ql, int qr, int k) {
if (r < ql || qr < l) return;
if (ql <= l && r <= qr) s[t] += k;
else {
int mid = l + r >> 1;
if (ql <= mid) add(t * 2, l, mid, ql, qr, k);
if (mid < qr) add(t * 2 + 1, mid + 1, r, ql, qr, k);
}
update(t, l, r);
}
} seg;
struct Graph {
int h[N], p[M], v[M], edge;
int l[N], r[N], id;
Graph(): edge(0), id(0) {}
void add(int a, int b) {
p[++edge] = h[a]; v[edge] = b; h[a] = edge;
}
void first_order(int x, int fa) {
l[x] = ++id;
forEach(x, vv, this)
if (vv != fa)
first_order(vv, x);
r[x] = id;
}
void add_subtree(int x, int k) {
seg.add(1, 1, n, l[x], r[x], k);
}
void add_node(int x, int k) {
seg.add(1, 1, n, l[x], l[x], k);
}
} g, p;
void work(int x, int fa) {
forEach(x,e,&p) {
g.add_subtree(p1[e], 1);
g.add_subtree(p2[e], 1);
}
g.add_node(x, 1);
ans[x] = seg.num[1] - 1;
g.add_node(x, -1);
forEach(x,v,&g)
if (v != fa)
work(v, x);
forEach(x,e,&p) {
g.add_subtree(p1[e], -1);
g.add_subtree(p2[e], -1);
}
}
int main() {
int i, a, b;
n = read(); m = read();
rep(i,1,n) a = read(), b = read(), g.add(a, b); g.add(b, a);
FOR(i,1,m) p1[i] = read(), p2[i] = read(), p.add(p1[i], i), p.add(p2[i], i);
g.first_order(1, 0);
work(1, 0);
FOR(i,1,n) printf("%d ", ans[i]);
return 0;
}