胡测6 (by Delov/lxhcr)
T1 数正方体
假设三视图中出现的正方形个数分别为 \(a,b,c\) ,容易想到当 \(a>bc\) 或 \(b>ac\) 或 \(c>ab\) 时,一定不存在满足条件的立体结构,测试大样例发现这是一个充要条件,因此我们需要求解的是:
以第一部分为例,简单推导有
容易发现 \(\max(ij)=AB\) ,显然这个数量级比 \(C\) 大,因此考虑用 \(C\) 限制 \(ij\) ,不妨设 \(i<j\) ,那么原式为:
直接 \(O(\sqrt C)\) 计算即可。
code
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int mod = 998244353, inv2 = mod + 1 >> 1;
int T;
long long A, B, C;
int Calc ( long long x, long long y, long long t )
{
int res = 0;
int lim = min(x, (long long)sqrt(t));
for ( int i = 1; i <= lim; i ++ )
{
long long L = i, R = min(y, t / i);
if ( L <= R )
{
int cnt = ( R - L ) % mod, sumL = ( 1 + L ) % mod * ( L % mod ) % mod * inv2 % mod, sumR = ( 1 + R ) % mod * ( R % mod ) % mod * inv2 % mod;
res = ( res + 1LL * cnt * ( t % mod ) % mod - 1LL * ( sumR - sumL + mod ) * i % mod + mod ) % mod;
}
}
lim = min(y, (long long)sqrt(t));
for ( int i = 1; i <= lim; i ++ )
{
long long L = i, R = min(x, t / i);
if ( L <= R )
{
int cnt = ( R - L ) % mod, sumL = ( 1 + L ) % mod * ( L % mod ) % mod * inv2 % mod, sumR = ( 1 + R ) % mod * ( R % mod ) % mod * inv2 % mod;
res = ( res + 1LL * cnt * ( t % mod ) % mod - 1LL * ( sumR - sumL + mod ) * i % mod + mod ) % mod;
}
}
lim = min(min(x, y), (long long)sqrt(t));
for ( int i = 1; i <= lim; i ++ )
res = ( res + ( t - 1LL * i * i ) % mod ) % mod;
return res;
}
void Work ()
{
scanf("%lld%lld%lld", &A, &B, &C);
int ans = ( A % mod ) * ( B % mod ) % mod * ( C % mod ) % mod;
ans = ( ans - Calc(A, B, C) + mod ) % mod;
ans = ( ans - Calc(A, C, B) + mod ) % mod;
ans = ( ans - Calc(B, C, A) + mod ) % mod;
printf("%d\n", ans);
return;
}
int main ()
{
freopen("cube.in", "r", stdin);
freopen("cube.out", "w", stdout);
scanf("%d", &T);
while ( T -- )
Work();
return 0;
}
T2 数树上点
很容易有一个朴素的 dp 想法,设 \(f_{u,i}\) 表示以 \(u\) 为根的子树,最浅点距离 \(u\) 为 \(i\) 时的方案数,转移时枚举 \(f_{u,i}\) 和 \(f_{v,j}\) 当 \(i+j+1\ge D\) 时更新 \(f_{u,\min(i,j+1)}\) 即可。
考虑进行优化,对上述 dp 做后缀和,设以 \(i\) 为根的 dp 数组的长度为 \(len_i\) ,容易发现转移可以在 \(O(\min(len_u,len_v+1))\) 的时间复杂度内完成,因此先做一次长链剖分可以做到 \(O(n)\) 。
code
#include <cstdio>
#include <algorithm>
using namespace std;
const int max1 = 2e6;
const int mod = 998244353;
int n, lim;
struct Node
{ int next, v; } edge[max1 * 2 + 5];
int head[max1 + 5], total;
int maxdeep[max1 + 5], deep[max1 + 5], father[max1 + 5], son[max1 + 5];
int in[max1 + 5], out[max1 + 5], dfs_clock;
int f[max1 + 5], g[max1 + 5], tmp[max1 + 5];
void Add ( int u, int v )
{
edge[++total].v = v;
edge[total].next = head[u];
head[u] = total;
return;
}
void Find_Long_Edge ( int now, int fa, int depth )
{
maxdeep[now] = deep[now] = depth, father[now] = fa, son[now] = 0;
for ( int i = head[now]; i; i = edge[i].next )
{
int v = edge[i].v;
if ( v == fa )
continue;
Find_Long_Edge(v, now, depth + 1);
if ( maxdeep[v] > maxdeep[now] )
maxdeep[now] = maxdeep[v], son[now] = v;
}
return;
}
void Connect_Long_Edge ( int now )
{
in[now] = out[now] = ++dfs_clock;
if ( son[now] )
{
Connect_Long_Edge(son[now]);
out[now] = out[son[now]];
}
for ( int i = head[now]; i; i = edge[i].next )
{
int v = edge[i].v;
if ( v == father[now] || v == son[now] )
continue;
Connect_Long_Edge(v);
}
return;
}
void Dfs ( int now )
{
if ( son[now] )
Dfs(son[now]);
f[in[now]] = 1;
if ( in[now] + 1 <= out[now] )
f[in[now]] = ( f[in[now]] + f[in[now] + 1] - 1 ) % mod;
if ( in[now] + lim <= out[now] )
f[in[now]] = ( f[in[now]] + f[in[now] + lim] ) % mod;
g[in[now]] = f[in[now]];
if ( in[now] + 1 <= out[now] )
g[in[now]] = ( g[in[now]] + g[in[now] + 1] ) % mod;
for ( int i = head[now]; i; i = edge[i].next )
{
int v = edge[i].v;
if ( v == father[now] || v == son[now] )
continue;
Dfs(v);
int minlen = out[v] - in[v] + 1;
for ( int k = in[now]; k <= in[now] + minlen; k ++ )
tmp[k] = f[k];
for ( int k = in[v]; k <= out[v]; k ++ )
f[in[now] + k - in[v] + 1] = ( f[in[now] + k - in[v] + 1] + f[k] ) % mod;
for ( int k = in[now]; k <= in[now] + minlen; k ++ )
{
int L = max(lim - k + in[now] + in[v] - 1, k - in[now] + in[v] - 1);
if ( L <= out[v] )
f[k] = ( f[k] + 1LL * tmp[k] * g[L] ) % mod;
}
for ( int k = in[v]; k <= out[v]; k ++ )
{
int L = max(lim - k + in[now] + in[v] - 1, k - in[v] + in[now] + 2);
if ( L <= out[now] )
f[in[now] + k - in[v] + 1] = ( f[in[now] + k - in[v] + 1] + 1LL * f[k] * g[L] ) % mod;
}
for ( int k = in[now] + minlen; k >= in[now]; k -- )
{
g[k] = f[k];
if ( k + 1 <= out[now] )
g[k] = ( g[k] + g[k + 1] ) % mod;
}
}
return;
}
int main ()
{
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
scanf("%d%d", &n, &lim);
for ( int i = 1, u, v; i <= n - 1; i ++ )
{ scanf("%d%d", &u, &v); Add(u, v), Add(v, u); }
Find_Long_Edge(1, 0, 0);
Connect_Long_Edge(1);
Dfs(1);
int ans = 0;
for ( int i = in[1]; i <= out[1]; i ++ )
ans = ( ans + f[i] ) % mod;
ans = ( ans + 1 ) % mod;
printf("%d\n", ans);
return 0;
}
T3 数区间集
我们定义一个区间是极大的当且仅当 \(a_{l-1},a_{r+1}\) 均不属于集合 \(\{a_l,a_{l+1},a_{l+2}...a_{r}\}\) ,容易发现统计极大的区间的个数会导致一些集合计算两次,但是这些集合所代表的的区间一定没有交集并且 \(r_1+1\ne l_2\) ,因此考虑减去这些集合的贡献,具体的,设 \(b_i\) 表示 \(i\) 前面第一个与 \(a_i\) 相同的数的位置,如果没有则 \(b_i=0\) ,考虑一组计算两次的区间 \([l_1,r_1]\) 和 \([l_2,r_2]\) ,考虑在 \(l_2\) 的位置计算答案,容易发现一定满足 \([l_2,r_2]\) 中所有的 \(b\) 均不为 \(0\) 并且满足 \(\max(b_i)-\min(b_i)-(r_2-l_2)=0\) ,由于区间内不存在相同的数,因此 \(\max(b_i)-\min(b_i)-(r_2-l_2)\ge 0\) ,可以用线段树维护最小值及个数统计答案,考虑这样统计会减去 \(r_1+1=l_2\) 的贡献,但容易发现这样的区间一定满足区间内 \(b\) 值最大,减去这样的区间的贡献即可。
code
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
const int max1 = 5e5;
const int inf = 0x3f3f3f3f;
int n, a[max1 + 5], b[max1 + 5], pos[max1 + 5];
long long ans;
struct Bit_Tree
{
#define lowbit(now) ( now & -now )
int tree[max1 + 5];
void Clear ()
{
for ( int i = 1; i <= n; i ++ )
tree[i] = 0;
return;
}
void Insert ( int now, int x )
{
while ( now <= n )
{
tree[now] += x;
now += lowbit(now);
}
return;
}
int Query ( int now )
{
int res = 0;
while ( now )
{
res += tree[now];
now -= lowbit(now);
}
return res;
}
int Query ( int L, int R )
{
return Query(R) - Query(L - 1);
}
}Tree1;
struct Data
{
int min_val, count;
Data () {}
Data ( int __min_val, int __count )
{ min_val = __min_val, count = __count; }
Data operator + ( const Data &A ) const
{
if ( min_val < A.min_val )
return *this;
else if ( min_val > A.min_val )
return A;
return Data(min_val, count + A.count);
}
};
struct Segment_Tree
{
#define lson(now) ( now << 1 )
#define rson(now) ( now << 1 | 1 )
struct Struct_Segment_Tree
{ Data d; int lazy; } tree[max1 * 4 + 5];
void Update ( int now, int x )
{
tree[now].d.min_val += x;
tree[now].lazy += x;
return;
}
void Push_Down ( int now )
{
if ( tree[now].lazy )
{
Update(lson(now), tree[now].lazy);
Update(rson(now), tree[now].lazy);
tree[now].lazy = 0;
}
return;
}
void Build ( int now, int L, int R )
{
tree[now].lazy = 0;
if ( L == R )
{ tree[now].d = Data(-L, 1); return; }
int mid = L + R >> 1;
Build(lson(now), L, mid);
Build(rson(now), mid + 1, R);
tree[now].d = tree[lson(now)].d + tree[rson(now)].d;
return;
}
void Insert ( int now, int L, int R, int ql, int qr, int x )
{
if ( L >= ql && R <= qr )
return Update(now, x);
Push_Down(now);
int mid = L + R >> 1;
if ( ql <= mid )
Insert(lson(now), L, mid, ql, qr, x);
if ( qr > mid )
Insert(rson(now), mid + 1, R, ql, qr, x);
tree[now].d = tree[lson(now)].d + tree[rson(now)].d;
return;
}
Data Query ( int now, int L, int R, int ql, int qr )
{
if ( L >= ql && R <= qr )
return tree[now].d;
Push_Down(now);
int mid = L + R >> 1;
Data res = Data(inf, 0);
if ( ql <= mid )
res = res + Query(lson(now), L, mid, ql, qr);
if ( qr > mid )
res = res + Query(rson(now), mid + 1, R, ql, qr);
return res;
}
}Tree2;
int maxs[max1 + 5], mins[max1 + 5], maxtop, mintop;
int main ()
{
freopen("seq.in", "r", stdin);
freopen("seq.out", "w", stdout);
scanf("%d", &n);
for ( int i = 1; i <= n; i ++ )
scanf("%d", &a[i]);
for ( int i = 1; i <= n; i ++ )
{ b[i] = pos[a[i]]; pos[a[i]] = i; }
Tree1.Clear();
for ( int i = 1; i <= n; i ++ )
{
Tree1.Insert(i, 1);
if ( b[i] )
Tree1.Insert(b[i] + 1, -1);
ans += Tree1.Query(b[i + 1] + 1, i);
}
Tree2.Build(1, 1, n);
maxs[0] = mins[0] = n + 1;
for ( int i = n; i >= 1; i -- )
{
if ( b[i] )
{
while ( maxtop && b[maxs[maxtop]] < b[i] )
{
Tree2.Insert(1, 1, n, maxs[maxtop], maxs[maxtop - 1] - 1, b[i] - b[maxs[maxtop]]);
--maxtop;
}
while ( mintop && b[mins[mintop]] > b[i] )
{
Tree2.Insert(1, 1, n, mins[mintop], mins[mintop - 1] - 1, b[mins[mintop]] - b[i]);
--mintop;
}
maxs[++maxtop] = i;
mins[++mintop] = i;
Data res = Tree2.Query(1, 1, n, i, maxs[0] - 1);
if ( res.min_val == -i )
ans -= res.count;
if ( !b[i - 1] && b[maxs[1]] == i - 1 )
{
res = Tree2.Query(1, 1, n, maxs[1], maxs[0] - 1);
if ( res.min_val == -i )
ans += res.count;
}
}
else
{
maxtop = mintop = 0;
maxs[0] = mins[0] = i;
}
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号