比赛链接
A
一、题意
定义一个函数。
如果存在,则
否则
二、题解
三、代码
B
一、题意
有一个无穷个节点的树,第个节点的父亲是。
是的最小质因子。
选择一个节点,求。
表示节点之间的边数,也就是距离,认为每条边的长度是。
多组测例。
数据范围:
二、题解
这题很麻烦,反正现在的我做的很别扭,2020.9.1。
显然要建立虚树。
通过画图,观察到下面这几个特性。
(1)
(2)
(3)
其中表示的最大质因子。
表示的的质因子个数。
第(3)条性质需要树状数组维护。
通过上面的性质可以建立出虚树。
这题就是求带权重心,贪心发现带权重心必然位于某个,因此带权重心位于虚树中,构造虚树是正确的。
然后换根求带权重心。
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << #x << " = " << x << '\n'
#define ddebug(x , y) cerr << #x << " = " << x << " " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int n ;
ll w[maxn] , dp[maxn] ;
ll sum[maxn] , S ;
int f[maxn] ;
int mindiv[maxn] ;
ll ans = 1e18 ;
void prework()
{
rep(i , 2 , 100000) for(int j = i ; j <= 100000 ; j += i) if(!mindiv[j]) mindiv[j] = i ;
rep(i , 2 , 100000) f[i] = f[i / mindiv[i]] + 1 ;
}
struct BIT
{
ll tree[maxn] ; //开 1 倍空间
void init(int n)
{
memset(tree , 0 , sizeof(ll) * (n + 5)) ;
}
int lowbit(int k)
{
return k & -k ;
}
void add(int n , int x , ll k) // a[x] += k
{
while(x <= n) //维护的是 [1 , n] 的序列
{
tree[x] += k ;
x += lowbit(x) ;
}
}
ll sum(int x) // sum[l , r] = sum(r) - sum(l - 1)
{
ll ans = 0 ;
while(x != 0)
{
ans += tree[x] ;
x -= lowbit(x) ;
}
return ans ;
}
ll query(int l , int r)
{
return sum(r) - sum(l - 1) ;
}
} bit ;
struct Virtual_tree
{
vector<int> vt[maxn] , vq ;
int top , stk[maxn] ;
bool vis[maxn] ;
int dep[maxn] ;
void init()
{
ans = 1e18 ;
dep[1] = 0 ;
rep(i , 2 , n)
{
dep[i] = dep[i - 1] + f[i] ;
int maxdiv = i ; //maxdiv是maxdiv[i]
while(maxdiv != mindiv[maxdiv]) maxdiv /= mindiv[maxdiv] ;
dep[n + i] = bit.query(maxdiv , n) ;
for(int j = i ; j != 1 ; j /= mindiv[j]) bit.add(n , mindiv[j] , 1) ;
}
}
void add(int u , int v)
{
vt[u].pb(v) , vt[v].pb(u) ;
}
void insert(int u)
{
if(top == 1) { stk[++ top] = u ; return ; }
int lc = n + u ; //lca预处理
if(dep[lc] == dep[stk[top]]) { stk[++ top] = u ; return ; }
while(top > 1 && dep[lc] <= dep[stk[top - 1]]) add(stk[top - 1] , stk[top]) , top -- ;
if(lc != stk[top]) add(lc , stk[top]) , stk[top] = lc ;
stk[++ top] = u ;
}
void build()
{
top = 0 , stk[++ top] = 1 ; //1不能在vq里面
rep(i , 2 , n) insert(i) ;
while(top >= 2) add(stk[top - 1] , stk[top]) , top -- ;
}
void dfs1(int f , int u)
{
dp[1] += w[u] * dep[u] ;
sum[u] = w[u] ;
for(auto v : vt[u]) if(v != f) dfs1(u , v) , sum[u] += sum[v] ;
}
void dfs2(int f , int u)
{
for(auto v : vt[u])
{
if(v == f) continue ;
ll d = dep[v] - dep[u] ;
dp[v] = dp[u] ;
dp[v] -= sum[v] * d ;
dp[v] += (S - sum[v]) * d ;
dfs2(u , v) ;
}
ans = min(ans , dp[u]) ;
cl(vt[u]) ; //清空,不能提前return结束遍历
}
} v_tree ;
int main()
{
ios ;
prework() ;
while(cin >> n)
{
S = 0 ;
rep(i , 1 , n) cin >> w[i] , w[n + i] = 0 , S += w[i] ;
dp[1] = 0 ;
bit.init(n) ;
v_tree.init() ;
v_tree.build() ;
v_tree.dfs1(1 , 1) ;
v_tree.dfs2(1 , 1) ;
cout << ans << '\n' ;
}
return 0 ;
}
C
一、题意
二、题解
三、代码
D
一、题意
二、题解
三、代码
E
一、题意
二、题解
三、代码
F
一、题意
定义是字符串a重复无穷次后的字符串。
判定和的字典序大小。
多组测例,保证
数据范围:
二、题解
脑洞题。
判定a+b和b+a的大小。
叉姐的严格证明:https://zhuanlan.zhihu.com/p/85169630
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << '*' << x << '\n'
#define ddebug(x , y) cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
const int mod = 998244353 ;
const int maxn = 2e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ;
string a , b , s , t ;
int main()
{
ios ;
while(cin >> a >> b)
{
s = a + b ;
t = b + a ;
int len = sz(s) ;
int flag = 2 ;
rep(i , 0 , len - 1)
if(s[i] < t[i]) { flag = 0 ; break ; }
else if(s[i] > t[i]) { flag = 1 ; break ; }
if(flag == 0) cout << "<\n" ;
else if(flag == 1) cout << ">\n" ;
else cout << "=\n" ;
}
return 0 ;
}
G
一、题意
二、题解
三、代码
H
一、题意
二、题解
三、代码
I
一、题意
个点条边的无向图,是否可以从中选择若干条边,使每个点的度数是。
多组测例。
数据范围:
二、题解
我参考了这位大哥的博客,侵删。
对每个度数拆点,对每条边拆点。
对这个测例举例子
4 4
1 2 1 0
1 2
1 4
2 3
3 4
为什么是对的?
可以发现有两种匹配边:
(1)拆点后的点与拆边后的点匹配。
(2)拆边后的点与拆边后的点匹配。
种类(1)表示保留原图(拆点前的图)的边。
种类(1)表示删除原图(拆点前的图)的边。
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << '*' << x << '\n'
#define ddebug(x , y) cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
const int mod = 998244353 ;
const int maxn = 3000 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ;
int n , m ;
vector<int> g[maxn] ;
struct blossemtree
{
queue<int> q ;
int fa[maxn] , type[maxn] , lk[maxn] , nxt[maxn] , vis[maxn] ;
int find(int x)
{
if(x == fa[x]) return x ;
return fa[x] = find(fa[x]) ;
}
void addedge(int u , int v)
{
//ddebug(u , v) ;
g[u].pb(v) , g[v].pb(u) ;
}
void combine(int x , int lca)
{
while(x != lca)
{
int u = lk[x] , v = nxt[u] ;
if(find(v) != lca) nxt[v] = u ;
if(type[u] == 1) type[u] = 2 , q.push(u) ;
fa[find(x)] = find(u) , fa[find(u)] = find(v) ;
x = v ;
}
}
void contrack(int x , int y)
{
int lca = x ;
memset(vis , 0 , (n + 1) * sizeof(int)) ;
for(int i = x ; i ; i = nxt[lk[i]]) i = find(i) , vis[i] = 1 ;
for(int i = y ; i ; i = nxt[lk[i]])
{
i = find(i) ;
if(vis[i])
{
lca = i ;
break ;
}
}
if(lca != find(x)) nxt[x] = y ;
if(lca != find(y)) nxt[y] = x ;
combine(x , lca) , combine(y , lca) ;
}
void bfs(int s)
{
memset(type , 0 , (n + 1) * sizeof(int)) ;
memset(nxt , 0 , (n + 1) * sizeof(int)) ;
rep(i , 1 , n) fa[i] = i ;
while(!q.empty()) q.pop() ;
q.push(s) , type[s] = 2 ;
while(!q.empty())
{
int x = q.front() ;
q.pop() ;
for(int y : g[x])
{
if(find(x) == find(y) || lk[x] == y || type[y] == 1) continue ;
if(type[y] == 2) contrack(x , y) ;
else if(lk[y]) nxt[y] = x , type[y] = 1 , type[lk[y]] = 2 , q.push(lk[y]) ;
else
{
nxt[y] = x ;
int pos = y , u = nxt[pos] , v = lk[u] ;
while(pos) lk[pos] = u , lk[u] = pos , pos = v , u = nxt[pos] , v = lk[u] ;
return ;
}
}
}
}
int maxmatch()
{
int ans = 0 ;
rep(i , 1 , n) if(!lk[i]) bfs(i) ;
rep(i , 1 , n) if(lk[i]) ans ++ ;
return ans / 2 ;
}
void init()
{
rep(i , 1 , n) cl(g[i]) ;
memset(lk , 0 , (n + 1) * sizeof(int)) ;
}
} T ;
int d[maxn] , in[maxn] ;
int a[maxn] , b[maxn] ;
pii id[maxn] ;
int main()
{
ios ;
int tot = 0 ;
ff : ;
while(cin >> n >> m)
{
tot = 0 ;
rep(i , 1 , n) cin >> d[i] ;
rep(i , 1 , m) cin >> a[i] >> b[i] , in[a[i]] ++ , in[b[i]] ++ ;
rep(i , 1 , n)
if(d[i] > in[i])
{
rep(i , 1 , n) in[i] = 0 ;
cout << "No\n" ;
goto ff ;
}
else if(d[i] == in[i]) id[i].fi = -1 , id[i].se = -2 ;
else id[i].fi = tot + 1 , id[i].se = tot + in[i] - d[i] , tot += in[i] - d[i] ;
rep(i , 1 , m)
{
int u = a[i] , v = b[i] ;
T.addedge(tot + 1 , tot + 2) ;
rep(i , id[u].fi , id[u].se) T.addedge(tot + 1 , i) ;
rep(i , id[v].fi , id[v].se) T.addedge(tot + 2 , i) ;
tot += 2 ;
}
n = tot ;
if(T.maxmatch() * 2 == tot) cout << "Yes\n" ;
else cout << "No\n" ;
rep(i , 1 , n) in[i] = 0 ;
T.init() ;
}
return 0 ;
}
J
一、题意
计算,答案对 取模。
多组测例,测例数
数据范围:
二、题解
原理是分部积分法
三、代码
#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define cl(x) x.clear()
#define all(x) x.begin() , x.end()
#define rep(i , x , n) for(int i = x ; i <= n ; i ++)
#define per(i , n , x) for(int i = n ; i >= x ; i --)
#define mem0(x) memset(x , 0 , sizeof(x))
#define mem_1(x) memset(x , -1 , sizeof(x))
#define mem_inf(x) memset(x , 0x3f , sizeof(x))
#define debug(x) cerr << '*' << x << '\n'
#define ddebug(x , y) cerr << '*' << x << ' ' << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
const int mod = 998244353 ;
const int maxn = 2e6 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
mt19937 rnd(chrono::high_resolution_clock::now().time_since_epoch().count()) ;
struct Easymath
{
ll qpow(ll a , ll b) //快速幂
{
if(b < 0) return 0 ;
ll ans = 1 ;
a %= mod ;
while(b)
{
if(b & 1) ans = (ans * a) % mod ;
b >>= 1 , a = (a * a) % mod ;
}
return ans % mod ;
}
ll ksc_log(ll x , ll y , ll mod) //快速乘
{
x %= mod , y %= mod ;
ll ans = 0;
while(y)
{
if(y & 1) ans = (ans + x) % mod ;
y >>= 1 ;
x = (x + x) % mod ;
}
return ans;
}
ll ksc_O1(ll x , ll y , ll mod) //快速乘
{
x %= mod , y %= mod ;
ll z = (ld)x * y / mod ;
ll ans = x * y - z * mod ;
if(ans < 0) ans += mod ;
else if(ans >= mod) ans -= mod ;
return ans ;
}
int cnt = 0 ;
bool vis[maxn] ;
int prime[maxn] ;
void get_prime(int up) //素数筛
{
memset(vis , 0 , sizeof(vis)) ;
vis[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
{
if(!vis[i])
prime[++ cnt] = i ;
for(int j = 1 ; j <= cnt && i * prime[j] <= up ; j ++)
{
vis[i * prime[j]] = 1 ;
if(i % prime[j] == 0) break ;
}
}
}
//begin 判定大素数
ll mul(ll a , ll b , ll mod)
{
ll ret = 0 ;
while(b)
{
if(b & 1) ret = (ret + a) % mod ;
a = (a + a) % mod ;
b >>= 1 ;
}
return ret ;
}
ll pow(ll a , ll b , ll mod)
{
ll ret = 1 ;
while(b)
{
if(b & 1) ret = mul(ret , a , mod) ;
a = mul(a , a , mod) ;
b >>= 1 ;
}
return ret ;
}
bool check(ll a , ll n)
{
ll x = n - 1 ;
int t = 0 ;
while((x & 1) == 0)
{
x >>= 1 ;
t ++ ;
}
x = pow(a , x , n) ;
ll y ;
rep(i , 1 , t)
{
y = mul(x , x , n) ;
if(y == 1 && x != 1 && x != n - 1) return 1 ;
x = y ;
}
if(y != 1) return 1 ;
return 0 ;
}
bool Miller_Rabin(ll n)
{
if(n == 2) return 1 ;
if(n == 1 || !(n & 1)) return 0 ;
const int arr[12] = {2,3,5,7,11,13,17,19,23,29,31,37} ;
rep(i , 0 , 11)
{
if(arr[i] >= n) break ;
if(check(arr[i] , n)) return 0 ;
}
return 1 ;
}
//end 判定大素数
ll get_inv(ll x) //逆元
{
return qpow(x , mod - 2) % mod ;
}
ll inv1[maxn] ; //乘法逆元
void init1(int up)
{
inv1[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
inv1[i] = (ll)(mod - mod / i) * inv1[int(mod % (ll)i)] % mod ;
}
ll fac[maxn] ;
ll inv[maxn] ; //阶乘逆元
void init(int up)
{
fac[0] = fac[1] = inv[0] = inv[1] = 1 ;
for(int i = 2 ; i <= up ; i ++)
{
fac[i] = fac[i - 1] * i % mod ;
inv[i] = -inv[mod % i] * (mod / i) % mod ;
while(inv[i] < 0) inv[i] += mod ;
}
for(int i = 2 ; i <= up ; i ++)
inv[i] = inv[i] * inv[i - 1] % mod ;
}
} em ;
int main()
{
ios ;
em.init(2000005) ;
int n ;
while(cin >> n)
{
ll ans = em.fac[n] * em.fac[n] % mod * em.inv[2 * n + 1] % mod ;
cout << ans << '\n' ;
}
return 0 ;
}