[题解向] 正睿Round409
Posted pks-t
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[题解向] 正睿Round409相关的知识,希望对你有一定的参考价值。
然而泥萌没有权限是看不了题目的233.
( m T1)
大概就是个map,脑残出题人认为(x,x)不属于有序二元组,我可qtmd。于是只拿了( m 60pts)
int main(){
ios_base :: sync_with_stdio(false) ;
cin.tie(0), cout.tie(0) ; cin >> N >> P ; int i ;
for (i = 1 ; i <= N ; ++ i) cin >> base[i], base[i] %= P ;
for (i = 1 ; i <= N ; ++ i) if (base[i]) M[expow(4 * base[i] % P, P - 2)] ++ ;
for (i = 1 ; i <= N ; ++ i){
int now = 1ll * base[i] * base[i] % P ;
ans += M[now] ; if (4ll * now % P * base[i] % P == 1) -- ans ;
}
cout << ans << endl ; return 0 ;
}
( m T2)
先说自己的做法。
发现其实就是在凑一个式子:
[frac{sum a_ik_i}{Msum k_i}=frac{N}{M}]
然后稍微变个形:
[sum a_ik_i=Ncdot sum k_i]
于是发现只要暴力背包就完了,最后判断一下(f_{k,N})是不是(=k)就做完了。
int main(){
cin >> K >> N >> M ; int i, j ; dp[0] = 0 ;
for (i = 1 ; i <= K ; ++ i) cin >> base[i] ;
for (i = 1 ; i <= N * N ; ++ i) dp[i] = Inf ;
for (i = 1 ; i <= K ; ++ i)
for (j = base[i] ; j <= N * N ; ++ j)
dp[j] = min(dp[j - base[i]] + 1, dp[j]) ;
for (i = 1 ; i <= N ; ++ i) if (dp[i * N] == i) return cout << i, 0 ;
return -1 ;
}
于是获得了(
m 70pts)……但是用头想一想,发现并不对。因为可能(f_{k,N})这个状态的(
m cost)可能是5,但是背包转移的时候只能记录最优状态,于是假设会记录4,那这个状态就挂掉了……对每个状态都开了个std :: set
发现T掉了……
正解是BFS。
考虑把式子转化一下,就变成了
[sum k_i(a_i-N)=0]
大概就是考虑用已经凑出的和当做状态,那么实际上是在找一个环。于是每次转移的时候枚举放哪个新物品(新物品权值为(a_i-N))就完了。
#define MAX 50000
cin >> K >> N >> M ; q.push(MAX) ; vis[MAX] = 1 ; int i ;
for (i = 1 ; i <= K ; ++ i) cin >> base[i], base[i] -= N ;
while (!q.empty()){
int now = q.front() ; q.pop() ;
if (now > M + MAX) continue ;
for (i = 1 ; i <= K ; ++ i){
if (now + base[i] == MAX){
cout << ans[now] + 1 << endl ;
return 0 ;
}
else if (!vis[now + base[i]])
vis[now + base[i]] = 1, ans[now + base[i]] = ans[now] + 1, q.push(now + base[i]) ;
}
}
cout << -1 << endl ;
正 解 暴 力, 菜 鸡 退 役。
( m T3)
sb题,每个连通块都产生( m 1)的贡献当且仅当没有任何一个连通块是树。
于是就变成了找树的问题……忘记前驱思考了nm老久,趁早退役算了= =
void dfs(int now, int pre){
vis[now] = 1 ;
for (int k = head[now] ; k ; k = E[k].next){
if (to(k) == pre) continue ;
if (to(k) == now) continue ;
if (!vis[to(k)]) dfs(to(k), now) ; else ++ o ;
}
}
int main(){
cin >> N ; int i ; p = 1 ;
for (i = 1 ; i <= N ; ++ i) fa[i] = i ;
for (i = 1 ; i <= N ; ++ i) cin >> base[i], add(i, base[i]) ;
for (i = 1 ; i <= N ; ++ i) if (fa[i] == i) ++ ans ;// cout << ans << endl ;
for (i = 1 ; i <= N ; ++ i) if (!vis[i]) o = 0, dfs(i, 0), p = min(o, p) ;
if (p) cout << ans << endl ; else cout << ans - 1 << endl ;
( m T4)
BZOJ4160.
不可做题233
题面:
给定一张无向图,求给这张图定向成( m DAG)之后最长路最短是多少。(nleq 16)
( m{Sol~1})
考虑直接(dp)。(f_{s,u,v})表示考虑了点集(s),最长路端点是(u,v)的最小值。每次转移的时候枚举(u,v,w),从((u,v),(v,w))两个状态转移到((u,w))。复杂度(O(3^nn^3))
1h没调出来
( m Sol~2)
考虑证明一个二级定理:
定理 (1.1)
- 一张无向图定向成的( m DAG),当其最长路最短时,其最长路为( m X-1),其中( m X)表示不连通集覆盖数。也就是对于一张有向图图( m {V,E}),定义一种划分(P),使得划分出的每个集合中所有点不连通。
考虑一种证明:
- 首先一定有( m X-1geq maxL)。因为其上的每个点是连通的。
- 其次我们考虑,如果每次删除全部出度为(0)点,放到一个集合里,那么一定合法,并且可以满足( m X=maxL+1)。
但其实这东西也可以直接用( m dilworth)定理的对偶定理证出来:
定理 (2.1)(( m dilworth)定理)
令( m (X,≤))是一个有限偏序集,并令(m)是反链的最大的大小。则( m X)可以被划分成(m)个但不能再少的链。
对偶一下:
定理 (2.2):
令( m (X,≤))是一个有限偏序集,并令(r)是其最大链的大小。则(X)可以被划分成(r)个但不能再少的反链。
然后”反链“连接的是”不可比的点“,也就是本题中”不连通的点“。
于是我们就可以快乐地状压了。
int *g, *f ;
int main(){
cin >> N >> M ;
memset(f, 63, sizeof(f)) ;
int u, v, i, j ; T = (1 << N) - 1 ;
for (i = 1 ; i <= M ; ++ i)
cin >> u >> v, -- u, -- v, E[u] |= (1 << v), E[v] |= (1 << u) ;
f[0] = 0, g[0] = 1 ;
for (i = 0 ; i <= N ; ++ i) Sz[1 << i] = i ;
for (i = 1 ; i <= T ; ++ i){
j = (i & (-i)) ;
if (!g[i ^ j]) continue ;
if (E[Sz[j]] & (i ^ j)) continue ;
g[i] = 1 ;
}
for (i = 1 ; i <= T ; ++ i)
for (j = i ; j ; j = (j - 1) & i)
if (g[j]) f[i] = min(f[i], f[i ^ j] + 1) ;
cout << f[T] - 1 << endl ; return 0 ;
}
以上是关于[题解向] 正睿Round409的主要内容,如果未能解决你的问题,请参考以下文章