题面又臭又长,我放个链接算了。
https://share.weiyun.com/5xk2rzi
T1
这个题考试的时候仔细想想应该可以切掉的。。。
先转换成计数问题,最后求一下逆元,除以区间个数就ok。
对于
的数据,可以按照题意模拟。
对于
的数据,观察到线段树上每个节点的贡献独立,枚举所有节点,一个节点的贡献是可以
计算的。
对于
的数据,观察到线段树上每一层的贡献独立,可以考虑如何求第
层对答案的贡献。
我们先考虑一个节点作为包含左端点的情况,因为它作为包含右端点的情况是和包含左端点一样的,我们只需要乘以
就可以了。
(被算x次意思是在x个区间查询里它有贡献)
在草稿纸上捣鼓几下可以发现,第
层所有的作为左儿子的节点总共要被算
次。
所有的作为右儿子的节点被计算的次数如下:
可以发现,第
层所有作为右儿子的节点被计算的次数构成了一个首项为1,末项为
,项数为
的等差数列。
套用等差数列求和公式,可得到所有右儿子计算次数为:
所以答案可以表示如下:
化简之后得到:
直接计算这个式子,复杂度
对于
的数据,关键是这个怎么算:
于是答案就是:
用快速幂
的时间计算答案,模数在int
范围内,不会爆long long
。
Code:
#include <cstdio>
#include <cstring>
#include <cstdlib>
typedef long long ll;
const ll P = 1e9 + 7;
ll pow(ll a, ll b)
{
a %= P;
ll ret = 1;
while (b)
{
if (b & 1) ret = ret * a % P;
a = a * a % P, b >>= 1;
}
return ret;
}
ll n;
int main()
{
//freopen("A.in", "r", stdin);
//freopen("A.out", "w", stdout);
scanf("%lld", &n);
ll p1 = pow(2, n - 1), p = p1 * 2 % P, p2 = p * 2 % P;
ll sum = (p1 + 1) * ((n - 1) % P * p2 % P + 2) % P;
printf("%lld\n", 2 * sum % P * pow(p, P - 2) % P * pow(p + 1, P - 2) % P);
fclose(stdin);
fclose(stdout);
return 0;
}
T2
大坑待填。
T3
对于
的数据,按照题意暴力。
对于
的随机数据,将询问离线,把每个点向上更新答案。
对于 的数据。考虑到各个质因子对答案的影响是独立的,因此可以分开统计,我们将每个点的 和询问的 都分解质因数,将质因数相同放在一起,容易得出其指数是所有指数与询问取 的和。我们可以按照指数排序,这样对于每个质因子,就是一个三维偏序问题:第一维是 序,修改的点要在询问子树内,第二维是深度,距离询问的点必须 ,第三位是指数,对于小于询问的指数,我们需要统计它们的和,对于大于询问的指数,我们只需要知道有多少个就行了。于是cdq分治一下,注意常数,就没问题了。
Code:
#include <vector>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N = 1e5 + 7, MAX = 1e7 + 7, P = 998244353;
inline int read()
{
int x = 0, f = 0;
char c = getchar();
for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = 1;
for (; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ '0');
return f ? -x : x;
}
inline int qpow(int a, int b)
{
int ret = 1;
while (b)
{
if (b & 1) ret = ret * 1ll * a % P;
a = a * 1ll * a % P, b >>= 1;
}
return ret;
}
int n, q, k, x[N], c[N];
struct note { int id, ct; };
vector<note> incl[MAX / 10];
int tot, tt, st[N], to[N << 1], nx[N << 1], dfn[N], out[N], dep[N], a[N];
void add(int u, int v) { to[++tot] = v, nx[tot] = st[u], st[u] = tot; }
int ret[N][2], ans[N];
struct ques { int typ, x, y, z, val; };
vector<ques> all[MAX / 10];
ques arr[N * 10];
int pr, check[MAX], prs[MAX / 10], mp[MAX];
void dfs(int u)
{
dfn[u] = ++tt;
for (int i = st[u]; i; i = nx[i]) if (!dfn[to[i]]) dep[to[i]] = dep[u] + 1, dfs(to[i]);
out[u] = tt;
}
void init()
{
for (int i = 2; i <= MAX - 7; i++)
{
if (!check[i]) prs[++pr] = i, mp[i] = pr;
for (int j = 1; j <= pr; j++)
{
if (i * prs[j] > MAX - 7) break;
check[i * prs[j]] = 1, mp[i * prs[j]] = j;
if (i % prs[j] == 0) break;
}
}
n = read(), q = read(), k = read() - 1;
for (int i = 1; i <= n; i++) a[i] = read();
for (int i = 1, u, v; i < n; i++) u = read(), v = read(), add(u, v), add(v, u);
dfs(1);
for (int i = 1; i <= q; i++) x[i] = read(), c[i] = read();
for (int i = 1; i <= q; i++)
{
ans[i] = 1;
while (c[i] > 1)
{
int cnt = 0, t = mp[c[i]];
while (c[i] % prs[t] == 0) c[i] /= prs[t], cnt++;
all[t].push_back((ques){i, out[x[i]], dep[x[i]] + k, cnt, 1});
all[t].push_back((ques){i, dfn[x[i]] - 1, dep[x[i]] + k, cnt, -1});
incl[t].push_back((note){i, cnt});
}
}
for (int i = 1; i <= n; i++)
while (a[i] > 1)
{
int cnt = 0, t = mp[a[i]];
while (a[i] % prs[t] == 0) a[i] /= prs[t], cnt++;
if (incl[t].empty()) continue;
all[t].push_back((ques){0, dfn[i], dep[i], cnt, 0});
}
}
int cmp(ques a, ques b) { return a.x == b.x ? a.typ < b.typ : a.x < b.x; }
int operator<(ques a, ques b) { return a.y <= b.y; }
int tr[2][40];
void add(int k, int po, int v) { for (; po <= 24; po += (po & (-po))) tr[k][po] += v; }
int getsum(int k, int po)
{
int s = 0;
for (; po; po -= (po & (-po))) s += tr[k][po];
return s;
}
void clear(int po) { for (; po <= 24; po += (po & (-po))) tr[0][po] = tr[1][po] = 0; }
ques tmp[N * 5];
void cdq(int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
cdq(l, mid), cdq(mid + 1, r);
int len = 0, p1 = l, p2 = mid + 1;
while (p1 <= mid && p2 <= r)
if (arr[p1] < arr[p2])
{
if (!arr[p1].typ) add(0, arr[p1].z, 1), add(1, arr[p1].z, arr[p1].z);
tmp[++len] = arr[p1++];
}
else
{
if (arr[p2].typ)
{
ret[arr[p2].typ][0] += arr[p2].val * (getsum(0, 24) - getsum(0, arr[p2].z));
ret[arr[p2].typ][1] += arr[p2].val * getsum(1, arr[p2].z);
}
tmp[++len] = arr[p2++];
}
while (p1 <= mid)
{
if (!arr[p1].typ) add(0, arr[p1].z, 1), add(1, arr[p1].z, arr[p1].z);
tmp[++len] = arr[p1++];
}
while (p2 <= r)
{
if (arr[p2].typ)
{
ret[arr[p2].typ][0] += arr[p2].val * (getsum(0, 24) - getsum(0, arr[p2].z));
ret[arr[p2].typ][1] += arr[p2].val * getsum(1, arr[p2].z);
}
tmp[++len] = arr[p2++];
}
memset(tr, 0, sizeof(tr));
for (int i = 1; i <= len; i++) arr[l + i - 1] = tmp[i];
}
void solve()
{
for (int i = 1; i <= pr; i++)
{
int siz = all[i].size();
if (incl[i].empty()) continue;
for (int j = 0; j < siz; j++) arr[j + 1] = all[i][j];
sort(arr + 1, arr + siz + 1, cmp);
int siz_ = incl[i].size();
for (int j = 0; j < siz_; j++)
{
int ind = incl[i][j].id;
ret[ind][0] = ret[ind][1] = 0;
}
cdq(1, siz);
for (int j = 0; j < siz_; j++)
{
int ind = incl[i][j].id;
ans[ind] = ans[ind] * 1ll * qpow(prs[i], incl[i][j].ct * ret[ind][0] + ret[ind][1]) % P;
}
}
for (int i = 1; i <= q; i++) printf("%d\n", ans[i]);
}
int main()
{
freopen("C.in", "r", stdin);
freopen("C.out", "w", stdout);
init();
solve();
fclose(stdin);
fclose(stdout);
return 0;
}
辣鸡出题人什么鬼题面。