数据结构之基环树——骑士,Island,旅行加强版,Number of Simple Paths,Traffic Network in Numazu,Card Game

文章目录

  • [ZJOI2008]骑士
  • [IOI2008] Island
  • [NOIP2018 提高组] 旅行 加强版
  • CF1454E Number of Simple Paths
  • Traffic Network in Numazu
  • Card Game

基环树的常见解法

  • 若干个基环树互相独立
  • 断环为链(随便断一条)
  • 环外树和环外树之间的树形DP
  • 环变链后整体可以用数据结构简单维护操作

[ZJOI2008]骑士

luogu2607

每个人都有讨厌的人,将这个条件转换成两人之间存在一条边

原图则转换成了若干个互不干扰的基环树

单独考虑一棵基环树

对于“树”的部分,可以树形DPDPDP

对于“环”的部分,不用单调队列,直接随便找一条环上边,强制断开

基环树就彻底变成了一棵树

设计dpu,0/1dp_{u,0/1}dpu,0/1转移

  • 父亲选,则所有儿子不能选
  • 父亲不选,则儿子可选可不选
  • 儿子之间也是互相独立的

分别以断开的边的两端作为树根,最后就是max(dp[S][0], dp[T][0])

为什么没有dp[S][1],dp[T][1]

  • S为例,dp[S][0]S为树根时强制不选的最大值
  • 此时TTT是树中一个节点,会根据转移方程式决定T是否选择
  • 如果dp[S][0]是不含TTT的,说明最佳方案本来就是S,T都不选择
  • 所以就不能出现dp[S][1],最佳方案可能包含了T
  • dp[T][0]同理
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define int long long 
#define maxn 1000005
int n, cnt, S, T, ID;
int w[maxn], head[maxn], to[maxn << 1], nxt[maxn << 1];
int dp[maxn][2];
bool vis[maxn];void addedge( int u, int v ) {to[cnt] = v, nxt[cnt] = head[u], head[u] = cnt ++;to[cnt] = u, nxt[cnt] = head[v], head[v] = cnt ++;
}void dfs1( int u, int id ) {vis[u] = 1;for( int i = head[u];~ i;i = nxt[i] ) {if( i == id ) continue;int v = to[i];if( vis[v] ) {S = u, T = v, ID = i;continue;}else dfs1( v, i ^ 1 );}
}void dfs2( int u, int id ) {dp[u][0] = 0, dp[u][1] = w[u];for( int i = head[u];~ i;i = nxt[i] ) {if( i == id or i == ID or i == ( ID ^ 1 ) ) continue;int v = to[i];dfs2( v, i ^ 1 );dp[u][0] += max( dp[v][0], dp[v][1] );dp[u][1] += dp[v][0];}
}signed main() {memset( head, -1, sizeof( head ) );scanf( "%lld", &n );for( int i = 1, x;i <= n;i ++ ) {scanf( "%lld %lld", &w[i], &x );addedge( i, x );}int ans = 0;for( int i = 1;i <= n;i ++ ) {if( vis[i] ) continue;dfs1( i, -1 );int t = 0;dfs2( S, -1 ); t = max( t, dp[S][0] );dfs2( T, -1 ); t = max( t, dp[T][0] );ans += t;}printf( "%lld\n", ans );return 0;
}

[IOI2008] Island

luogu4381

同样的,这是相互独立的若干棵基环树

问题转化为求若干个基环树的直径之和

单独考虑一个基环树,设计状态转移方程

边权变成入点的点权

fi:if_i:ifi:i子树内以iii为链端的最长链长度

gi:ig_i:igi:i子树内的直径

首先可以利用拓扑做有向图,求出所有的环,顺便转移出每个点的信息

  • v∈sonuv\in son_uvsonu
  • 直径是vvv子树内的直径
    • gu=max⁡(gu,gv)g_u=\max(g_u,g_v)gu=max(gu,gv)
  • 直径是由uuu的两条链拼接而成,其中一条链过vvv
    • gu=max⁡(fu+fv+wu,v,gu)g_u=\max(f_u+f_v+w_{u,v},g_u)gu=max(fu+fv+wu,v,gu)
  • 最长链为vvv这一条链
    • fu=max⁡(fu,fv+wu,v)f_u=\max(f_u,f_v+w_{u,v})fu=max(fu,fv+wu,v)

考虑环上的点信息更新

  • 基环树直径可能是某个点的环外子树直径
  • 基环树直径可能是两个环点的最长链拼接,再加上环上距离

同样的,枚举环上某一条边,强制断边,变成一条单链后

可以用前缀和差分求环上两点的距离,距离有两种

  • 恰好顺着断边的顺序
    • sumj−sumisum_j-sum_isumjsumi
  • 反着走环
    • len−(sumj−sumi)len-(sum_j-sum_i)len(sumjsumi)

则环上点拼接成直径的转移为

max⁡(fi+fj+sumj−sumi,fi+fj+len−sumj+sumi)\max(f_i+f_j+sum_j-sum_i,f_i+f_j+len-sum_j+sum_i)max(fi+fj+sumjsumi,fi+fj+lensumj+sumi)

发现i,ji,ji,j之间是独立的,枚举到jjj时,记录前面最大贡献的iii

Max1=max⁡{fi−sumi};Max2=max⁡{fi+sumi}Max_1=\max\{f_i-sum_i\};Max_2=\max\{f_i+sum_i\}Max1=max{fisumi};Max2=max{fi+sumi}

max⁡(fj+sumj+Max1,fj+len−sumj+Max2)\max(f_j+sum_j+Max_1,f_j+len-sum_j+Max_2)max(fj+sumj+Max1,fj+lensumj+Max2)

但是只有当环跑完后我们才知道环长lenlenlen

所以可以把lenlenlen提出去,最后加上再选较大值

#include <queue>
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
#define maxn 1000005
queue < int > q;
int to[maxn], d[maxn], w[maxn], f[maxn], g[maxn];
bool vis[maxn];
int n;int dfs( int now ) {int x = to[now], sum = w[now];int ans1 = g[now], Max1 = f[now];int ans2 = - 1e18, Max2 = f[now];while( x ^ now ) {d[x] = 0;ans1 = max( ans1, g[x] );ans1 = max( ans1, f[x] + sum + Max1 );ans2 = max( ans2, f[x] - sum + Max2 );Max1 = max( Max1, f[x] - sum );Max2 = max( Max2, f[x] + sum );sum += w[x];x = to[x];}return max( ans1, ans2 + sum );
}signed main() {scanf( "%lld", &n );	for( int i = 1;i <= n;i ++ )scanf( "%lld %lld", &to[i], &w[i] ), d[to[i]] ++;for( int i = 1;i <= n;i ++ )if( ! d[i] ) q.push( i );while( ! q.empty() ) {int u = q.front(); q.pop();int v = to[u];g[v] = max( g[v], max( g[u], f[v] + f[u] + w[u] ) );f[v] = max( f[v], f[u] + w[u] );d[v] --;if( ! d[v] ) q.push( v );}int ret = 0;for( int i = 1;i <= n;i ++ ) if( d[i] ) ret += dfs( i );printf( "%lld\n", ret );return 0;
}

[NOIP2018 提高组] 旅行 加强版

luogu5049

  • m=n-1
    • 就是单纯的一棵树,直接dfs搜就可以了
  • m=n
    • 基环树

一个点只能访问未访问点,或者选择回溯

考虑对于基环树环上点的几种选择

  • case1

在这里插入图片描述

对于节点3,肯定是由2过来的,最佳选择是先遍历完非环的树的点5,6,再走环

是不会选择回溯到2的

  • case2

在这里插入图片描述

3的环边5是其所有边中最小的,优选走环,后遍历非环树,不选择回溯

  • case3

在这里插入图片描述

3的环边6不是最大也不是最小,选择先遍历5再走环边,最后遍历8,同样不会选择回溯

发现只有当环边是最大边的时候就会选择遍历完非环树后回溯

但真的这样就直接回溯了吗?

  • case4

在这里插入图片描述

走到3的时候,遍历5,6,但是发现回溯后走的是9并没有比8小,也是应该不回溯的

综上,只有环边是最大边且比回溯后走的第一条边大的时候才会选择回溯

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 500005
vector < int > ans;
struct node { int u, v; }edge[maxn << 1];
int head[maxn], to[maxn << 2], nxt[maxn << 2], f[maxn];
bool vis[maxn], circle[maxn];
bool flag1, flag2, flag3;
int n, m, cnt, Max;void dfs1( int u ) {vis[u] = 1;ans.push_back( u );for( int i = head[u];~ i;i = nxt[i] ) {int v = to[i];if( vis[v] ) continue;else dfs1( v );}
}void dfs2( int now, int fa ) {if( flag2 ) return;if( ! f[now] ) f[now] = fa;else {do {circle[fa] = 1;fa = f[fa];} while( fa ^ f[now] );flag2 = 1;return;}for( int i = head[now];~ i;i = nxt[i] )if( to[i] ^ fa ) dfs2( to[i], now );
}void dfs3( int u ) {vis[u] = 1;ans.push_back( u );if( circle[u] ) {bool flag = 0;for( int i = head[u];~ i;i = nxt[i] ) {if( flag3 ) break;if( ! circle[to[i]] or vis[to[i]] ) continue;int v = to[i];i = nxt[i];while( vis[to[i]] ) i = nxt[i];if( ~ i ) Max = to[i];else if( v > Max ) flag = flag3 = 1;break;}for( int i = head[u];~ i;i = nxt[i] ) if( vis[to[i]] or ( flag and circle[to[i]] ) ) continue;else dfs3( to[i] );}elsefor( int i = head[u];~ i;i = nxt[i] )if( vis[to[i]] ) continue;else dfs3( to[i] );
}int main() {scanf( "%d %d", &n, &m );if( m == n - 1 ) flag1 = 1;for( int i = 1, u, v;i <= m;i ++ ) {scanf( "%d %d", &u, &v );edge[i] = { u, v };edge[i + m] = { v, u };}m <<= 1;sort( edge + 1, edge + m + 1, []( node x, node y ) { return x.v > y.v; } );memset( head, -1, sizeof( head ) );for( int i = 1;i <= m;i ++ ) {int u = edge[i].u, v = edge[i].v;to[cnt] = v, nxt[cnt] = head[u], head[u] = cnt ++;}if( flag1 ) dfs1( 1 );else {dfs2( 1, 0 );Max = 1e9;dfs3( 1 );}for( auto i : ans ) printf( "%d ", i );return 0;
}

CF1454E Number of Simple Paths

CF1454E

非常简单

跑出环和非环树

  • 两个点隶属于同一个环点的非环树(之间不会经过环)
    • 从子树大小中选两个数,siz∗(siz−1)/2siz*(siz-1)/2siz(siz1)/2
  • 经过环的两点之间的方案数有两种(走环的不同方向)
    • 从子树中选一个,在子树外选一个,siz∗(n−siz)/2∗2=siz∗(n−siz)siz*(n-siz)/2*2=siz*(n-siz)siz(nsiz)/22=siz(nsiz)
#include <cstdio>
#include <vector>
using namespace std;
#define int long long
#define maxn 200005
vector < int > G[maxn];
int T, n;
bool flag;
int f[maxn], siz[maxn];
bool circle[maxn];void dfs1( int u, int fa ) {if( flag ) return;if( ! f[u] ) f[u] = fa;else {do {circle[fa] = 1;fa = f[fa];} while( f[u] ^ fa );flag = 1;return;}for( auto v : G[u] ) if( v ^ fa ) dfs1( v, u );
}void dfs2( int u, int fa ) {siz[u] = 1;for( auto v : G[u] ) {if( v == fa or circle[v] ) continue;else dfs2( v, u ), siz[u] += siz[v];}
}signed main() {scanf( "%lld", &T );while( T -- ) {scanf( "%lld", &n );flag = 0;for( int i = 1;i <= n;i ++ ) circle[i] = f[i] = 0, G[i].clear();for( int i = 1, u, v;i <= n;i ++ ) {scanf( "%lld %lld", &u, &v );G[u].push_back( v );G[v].push_back( u );}dfs1( 1, 0 );int ans = 0;for( int i = 1;i <= n;i ++ )if( circle[i] ) {dfs2( i, 0 );ans += siz[i] * ( siz[i] - 1 ) / 2 + siz[i] * ( n - siz[i] );}printf( "%lld\n", ans );}return 0;
}

Traffic Network in Numazu

HDU6393

同样的,断环为链

两点间的距离分为三种

  • 两点在同一棵非环树内,直接求出两个点的lca,再计算
  • 经过环
    • 两点到环的两端,然后加上断的边长
    • 两点到环的相反两端,然后加上断的边长

利用线段树可以维护,但是树状数组更好写

断树后进行dfn序的重置,修改一条边其实是对于一个连续区间的修改

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define int long long
#define maxn 100005
struct node { int u, v, w; }E[maxn];
vector < node > G[maxn];
int Ti, n, Q, cnt, S, T, id, len;
int L[maxn], R[maxn], t[maxn], f[maxn], dep[maxn];
int p[maxn][20];int lowbit( int i ) { return i & -i; }void modify( int i, int val ) {for( ;i <= n;i += lowbit( i ) ) 	t[i] += val;
}int query( int i ) {int ans = 0;for( ;i;i -= lowbit( i ) )ans += t[i];return ans;
}int find( int x ) { return x == f[x] ? x : f[x] = find( f[x] ); }void dfs( int u, int fa, int w ) {dep[u] = dep[fa] + 1;p[u][0] = fa;for( int i = 1;i < 20;i ++ )p[u][i] = p[p[u][i - 1]][i - 1];L[u] = ++ cnt;modify( L[u], w );for( auto i : G[u] )if( i.v ^ fa ) dfs( i.v, u, i.w );R[u] = cnt;modify( R[u] + 1, -w );
}int lca( int u, int v ) {if( dep[u] < dep[v] ) swap( u, v );for( int i = 19;~ i;i -- )if( dep[p[u][i]] >= dep[v] )u = p[u][i];if( u == v ) return u;for( int i = 19;~ i;i -- )if( p[u][i] ^ p[v][i] )u = p[u][i], v = p[v][i];return p[u][0];
}int dis( int x, int y ) {return query( L[x] ) + query( L[y] ) - query( L[lca( x, y )] ) * 2;
}signed main() {scanf( "%lld", &Ti );while( Ti -- ) {scanf( "%lld %lld", &n, &Q );cnt = 0;for( int i = 1;i <= n;i ++ ) {G[i].clear();f[i] = i;t[i] = 0;for( int j = 0;j < 20;j ++ )p[i][j] = 0;}for( int i = 1, u, v, w;i <= n;i ++ ) {scanf( "%lld %lld %lld", &u, &v, &w );if( find( u ) == find( v ) )S = u, T = v, id = i, len = w;else {G[u].push_back( { u, v, w } );G[v].push_back( { v, u, w } );E[i] = { u, v, w };f[find( v )] = find( u );}}dfs( 1, 0, 0 );	for( int i = 1, opt, x, y;i <= Q;i ++ ) {scanf( "%lld %lld %lld", &opt, &x, &y );if( ! opt ) if( x == id ) len = y;else {int now = p[E[x].u][0] == E[x].v ? E[x].u : E[x].v;modify( L[now], y - E[x].w );modify( R[now] + 1, E[x].w - y );E[x].w = y;}else printf( "%lld\n", min( dis( x, y ), min( dis( x, S ) + dis( y, T ), dis( x, T ) + dis( y, S ) ) + len ) );}}return 0;
}

Card Game

HDU6403


一张牌的两面,要求朝上面的数字互不相同

显然是将牌的两面连边,一条边也就代表一张牌,数字互不相同就是选择不同的点

  • 对于“树”的方案
    • 钦定其中某个点不选,则剩下的点都被钦定,方案数为树的大小
  • 对于“环”的方案
    • 只有两种方案(均选左和均选右)

这是很基础的“牌的两面”基环树应用的处理方法


转回此题,题目可以翻译为

将牌的反面向正面连边,求反转最少边数的方案数,使得每个点的入度不超过1

显然当且仅当图为树或基环树的时候才有解

且此题很有可能有重边和自环

同样的将环拆成链后再单独考虑被强断的那条边的贡献

对于树就单纯的树形DPDPDP

具体而言

  • 求出每个连通块的点数和边数

  • 若边数不是点数或者点数减一,就无解

  • 若边数等于点数,说明是个基环树

    • 断开一条边后以边的两端开始遍历一遍分别求出最少反转的边数

      (边数跟连边的边权有关,下面有阐释)

    • 如果加上这条边的贡献相同方案数为2,否则为1

  • 若边数等于点数减一,说明是个普通的树

    • 树形DPDPDP,求出以每个点为根(钦定不选)的最少反转次数

    • 其实最少反转数在换根DPDPDP父亲向儿子转移的时候才会发生变化,且变化只有111

      如何根据边权推测变化+1或者-1

      • 对于一张牌,正面向反面建边权为1,反面向正面建边权为0
      • uuu不选时的答案为dpudp_udpu,转移到儿子vvv不选时
      • 如果u→vu\rightarrow vuv的边权为1,说明一张牌本来是uuu在上,dpudp_udpu为了不选uuu将其反转了
      • 那么变成不选vvv时,就需要选择uuu,这张牌就变成了不反转,操作次数就减一
      • 所以dpv=dpu−1dp_v=dp_u-1dpv=dpu1
      • 反之自然是dpv=dpu+1dp_v=dp_u+1dpv=dpu+1
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define int long long
#define mod 998244353
#define maxn 200005
int Case, n, node, edge, cnt, S, T, id, top;
int head[maxn], to[maxn], nxt[maxn], w[maxn], f[maxn], g[maxn], dp[maxn];
bool vis[maxn];void dfs1( int now ) {vis[now] = 1;node ++;for( int i = head[now];~ i;i = nxt[i] ) {edge ++;if( ! vis[to[i]] ) dfs1( to[i] );}
}void dfs2( int now, int ID ) {vis[now] = 1;f[now] = 0;for( int i = head[now];~ i;i = nxt[i] ) {if( i == ID ) continue;if( ! vis[to[i]] ) {dfs2( to[i], i ^ 1 );f[now] += f[to[i]] + w[i];}else S = now, T = to[i], id = i;}
}void dfs3( int now, int ID ) {dp[++ top] = g[now];for( int i = head[now];~ i;i = nxt[i] )if( i == ID or i == ( id ^ 1 ) or i == id ) continue;else {g[to[i]] = g[now] + ( w[i] ? -1 : 1 );dfs3( to[i], i ^ 1 );}
}signed main() {scanf( "%lld", &Case );nxt :while( Case -- ) {scanf( "%lld", &n );memset( head, -1, sizeof( head ) );memset( vis, 0, sizeof( vis ) );cnt = 0;for( int i = 1, x, y;i <= n;i ++ ) {scanf( "%lld %lld", &x, &y );w[cnt] = 1, to[cnt] = y, nxt[cnt] = head[x], head[x] = cnt ++;w[cnt] = 0, to[cnt] = x, nxt[cnt] = head[y], head[y] = cnt ++;}for( int i = 1;i <= n;i ++ )if( ! vis[i] ) {node = edge = 0;dfs1( i );edge >>= 1;if( edge > node ) {printf( "-1 -1\n" );goto nxt;}}memset( vis, 0, sizeof( vis ) );int ret = 0, ans = 1; n <<= 1;for( int i = 1;i <= n;i ++ )if( ! vis[i] ) {S = T = cnt = top = 0, id = -1;dfs2( i, -1 );g[i] = f[i];dfs3( i, -1 );if( ! S ) {sort( dp + 1, dp + top + 1 );for( int j = 1;j <= top;j ++ )if( dp[j] == dp[1] ) cnt ++;else break;ret += dp[1];}else {id &= 1;if( g[S] + id == g[T] + ( id ^ 1 ) ) cnt = 2;else cnt = 1;ret += min( g[S] + id, g[T] + ( id ^ 1 ) );}ans = ans * cnt % mod;}printf( "%lld %lld\n", ret, ans );}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/317141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1090. 绿色通道

1090. 绿色通道 题意&#xff1a; n个题&#xff0c;每个题所花时间为ai&#xff0c;最多只用不超过t分钟做这个&#xff0c;肯定会有题目做不完&#xff0c;下标连续的一些空题称为一个空题段&#xff0c;问在t分钟内最长的空题段至少有多长&#xff1f; 题解&#xff1a; …

模板:BSGS(数论)

所谓 BSGS&#xff0c;就是北上广深。 &#xff08;逃&#xff09; BSGS 给出 a,b,pa,b,pa,b,p&#xff0c;请处出满足 ax≡b(modp)a^x\equiv b\pmod pax≡b(modp) 的最小非负正数解或者报告无解。 a,b,p≤109,gcd⁡(a,p)1a,b,p\le 10^9,\gcd(a,p)1a,b,p≤109,gcd(a,p)1 由于 …

如何在ASP.NET Core中自定义Azure Storage File Provider

主题&#xff1a;如何在ASP.NET Core中自定义Azure Storage File Provider作者&#xff1a; Lamond Lu地址: https://www.cnblogs.com/lwqlun/p/10406566.html项目源代码&#xff1a; https://github.com/lamondlu/AzureFileProvider背景ASP.NET Core是一个扩展性非常高的框架…

splay/fhq-treap 问卷调查反馈—— [JSOI2008]火星人prefix(splay),Strange Queries(fhq-treap)

文章目录[JSOI2008]火星人prefixStrange Queries[JSOI2008]火星人prefix BZOJ1014 思路很好想&#xff0c;哈希字符串即可 只是平衡树的码量大 注意因为splay加入哨兵的原因&#xff0c;每个点在平衡树内的排名比真实排名大111&#xff08;有极小值的占位&#xff09; 考虑…

AcWing 1091. 理想的正方形

AcWing 1091. 理想的正方形 题意&#xff1a; 有一个 ab 的整数组成的矩阵&#xff0c;现请你从中找出一个 nn 的正方形区域&#xff0c;使得该区域所有数中的最大值和最小值的差最小。 题解&#xff1a; 前置知识&#xff1a;已经学会了一维的单调队列优化dp 在本题中要求…

美好生活从撸好代码开始

楔子 昨天晚上做了个梦&#xff0c;梦到老板对我说了一番道理&#xff0c;他说对家庭要用爱心&#xff0c;做人对社会要有包容心&#xff0c;对工作要有责任心&#xff0c;对老板要有同理心。 我深以为然。现在的老板确实太不容易了&#xff0c;尤其是作为一家承载梦想&#xf…

模板:莫比乌斯反演(数论)

文章目录前言整除分块代码积性函数线性筛狄利克雷卷积莫比乌斯反演trick所谓莫比乌斯反演&#xff0c;就是莫比乌斯进行的反演 &#xff08;逃&#xff09; 前言 在一些需要整除的式子和 gcd⁡,lcm⁡\gcd,\operatorname{lcm}gcd,lcm 等问题中发挥作用。 整除分块 整除分块是…

[TJOI2013]拯救小矮人(反悔贪心证明),「ICPC World Finals 2019」Hobson 的火车(基环树,差分)

2021-09-07 test[TJOI2013]拯救小矮人「ICPC World Finals 2019」Hobson 的火车[TJOI2013]拯救小矮人 luogu4823 考试题目的数据加强为2e5&#xff0c;所以此题做法应为O(nlog⁡n)O(n\log n)O(nlogn)的反悔贪心 这种有多元属性&#xff0c;选择最优的问题 如果发现简单的贪心…

Dotnet全平台下APM-Trace探索

随着支撑的内部业务系统越来越多&#xff0c;向着服务化架构进化&#xff0c;在整个迭代过程中&#xff0c;会逐渐暴露出以下问题。传统依赖于应用服务器日志等手段的排除故障原因的复杂度越来越高&#xff0c;传统的监控服务已经无法满足需求。终端--> Nginx --> IIS --…

生成函数全家桶

文章目录有用的式子1.&#xff08;牛顿二项式定理&#xff09;2.普通生成函数&#xff08;OGF&#xff09;常见封闭形式&#xff1a;1.2.3.4.指数生成函数&#xff08;EGF&#xff09;排列与圆排列有用的式子 1.&#xff08;牛顿二项式定理&#xff09; 我们把组合数的定义推…

2020年牛客多校第五场C题-easy(纯组合计数不要生成函数的做法)

文章目录descriptionsolutioncodedescription 有TTT组测试数据 对于两个长度为KKK的数列{a}\{a\}{a}和{b}\{b\}{b}&#xff0c;满足∑i1KaiN,∑i1KbiM\sum_{i1}^Ka_iN,\sum_{i1}^Kb_iM∑i1K​ai​N,∑i1K​bi​M 对于这两个数列&#xff0c;定义权值为P∏i1Kmin⁡(ai,bi)P\p…

部署Chart应用并使用.net core读取Kubernetes中的configMap

上一篇文章讲了 k8s使用helm打包chart并上传到腾讯云TencentHub&#xff0c;今天就讲一下使用Helm部署应用并使用configMap代替asp.net core 中的appsettings.json文件。把Chart上传到TencentHub之后&#xff0c;我们就可以通过腾讯云的容器服务&#xff0c;直接部署Helm应用了…

Vases and Flowers HDU - 4614

Vases and Flowers HDU - 4614 题意: 一排空瓶子放花&#xff0c;操作1&#xff1a;从第x个瓶子开始放花&#xff0c;放y朵花&#xff0c;每个瓶子就一朵花&#xff0c;如果碰到已经有花的瓶子跳过这个瓶子&#xff0c;看下一个&#xff0c;当花没了&#xff0c;或者瓶子不够…

洛谷P3327:[SDOI2015]约数个数和(莫比乌斯反演)

枚举倍数的一种灵活的变形&#xff1a;g(d)∑d∣inf(i)∑i1⌊nd⌋f(i⋅d)g(d)\sum_{d|i}^nf(i)\sum_{i1}^{\lfloor\frac{n}{d}\rfloor}f(i\cdot d)g(d)∑d∣in​f(i)∑i1⌊dn​⌋​f(i⋅d) 很显然&#xff0c;但有时能发挥大作用。 其实本质还是要理解西格玛究竟是在算什么 解析…

EFCore Lazy Loading + Inheritance = 干净的数据表 (一)

前言α角 与 β角关于α角 与 β角的介绍&#xff0c;请见上文 如何用EFCore Lazy Loading实现Entity Split。本篇会继续有关于β角的彩蛋在等着大家去发掘。/斜眼笑其他本篇的程序&#xff0c;可以在 https://github.com/kentliu2007/EFCoreDemo/tree/master/InheritanceWithE…

专题突破之反悔贪心——建筑抢修,Cow Coupons G, Voting (Hard Version),Cardboard Box

文章目录[JSOI2007]建筑抢修[USACO12FEB]Cow Coupons GCF1251E2 Voting (Hard Version)CF436E Cardboard Box[JSOI2007]建筑抢修 luogu4053 将建筑按照结束时间从小到大排序 然后记录一下已经修理的建筑总共的花费时间 如果花费时间加上现在这个建筑的修建时间超过了这个建…

Max Sum Plus Plus HDU - 1024

Max Sum Plus Plus HDU - 1024 题意&#xff1a; 给你n个数&#xff0c;选m个子段&#xff0c;各个子段连续且不相交&#xff0c;长度可以为1&#xff0c;设maxn为各个子区间的和&#xff0c;求最大的maxn。 题解&#xff1a; 设dp[i][j]表示前j个数分成i段的最大值 对于第…

模板:杜教筛(莫比乌斯反演、数论)

所谓杜教筛&#xff0c;就是dms教给我们的筛 &#xff08;逃&#xff09; 前言 与其说算法&#xff0c;不如说是技巧。 可以在低于线性的时间复杂度&#xff08;准确的说是 O(n23)O(n^{\frac{2}{3}})O(n32​)&#xff09;内完成对积性函数的前缀和计算。 解析 考虑求函数 f…

程序员过关斩将--快速迁移10亿级数据

菜菜呀&#xff0c;咱们业务BJKJ有个表数据需要做迁移程序员主力 Y总现在有多少数据&#xff1f;菜菜大约21亿吧&#xff0c;2017年以前的数据没有业务意义了&#xff0c;给你半天时间把这个事搞定&#xff0c;绩效给你A程序员主力 Y总有绩效奖金吗&#xff1f;菜菜钱的事你去问…

[2021-09-09 T2] 就差⼀点——冒泡排序和反序表之间不为人知的秘密

就差一点解题报告descriptionsolutioncodedescription 题目描述 冒泡排序是⼀个简单的排序算法&#xff0c;其时间复杂度为O(n2)O(n^2)O(n2) 有⼀个大小为nnn的排列p1,...,pnp_1,...,p_np1​,...,pn​&#xff0c;⼩明想对这个排列进⾏冒泡排序&#xff0c;于是写了下⾯这份…