自己出的水題的題解
小小地整理一下我近幾天(周)出的題……也不算特別難吧
小小的寫一下\(\rm{Solution}\)
\(T1:\)
顯然是個遞推,我們思考第一個情況,對於新加進來的一個物體,他要麼自成一圈,要麼加入到剩下的空裡面。而\(n-1\)個物品的圓排列總共有\(n-1\)個空隙。所以:
我們用\(f_{i,j}\)表示\(i\)個物體,組成\(j\)個圓排列的方案數。那麼這個東西的轉移就是
\(f_{i,j} = f_{i-1,j - 1} + (i - 1) \times f_{i - 1,j}\)
哦對,說一下,圓排列本質相同的定義是通過自身旋轉可以得到的所有排列,與自身本質相同——注意是旋轉而不是對稱
第二個就更簡單了吧,新加進來的物體,要麼加入到以前的\(j-1\)個集合裡面,要麼就直接自成一集合。所以遞推式為:
\(f_{i, j} = f_{i - 1,j-1} + j \times f_{i-1,j}\)
#include <cstdio> #include <iostream> #define MAX 7010 #define ll long long #define Mod 993244853 using namespace std ; string Mark ; int S[MAX][MAX], s[MAX][MAX], i, j, q, Last, Max, N, K ; inline ll power(ll A, ll B){ ll Ans = 1 ; while(B){ if (B & 1) Ans = (long long)Ans * (long long)A % Max ; A = (long long)A * (long long)A % Max, B >>= 1 ; } return Ans ; } int main(){ cin >> Max >> q ; Last = 1, s[0][0] = S[0][0] = 1 ; for (i = 1 ; i <= Max ; ++ i) for (j = 1 ; j <= Max ; ++ j) S[i][j] = ((long long)S[i - 1][j - 1] + (long long)j * (long long)S[i - 1][j] % Mod) % Mod, s[i][j] = ((long long)s[i - 1][j - 1] + (long long)(i - 1) * (long long)s[i - 1][j] % Mod) % Mod; while(q --){ cin >> Mark ; scanf("%d%d", &N, &K) , N = power(N, Last + 1) + 1, K %= N, ++ K ; if (Mark[0] == 'A') printf("%d\n", Last = s[N][K]) ; else printf("%d\n", Last = S[N][K]) ; } return 0 ; }
\(T2:\)
題目其實就是在求樹上的最小點覆蓋(染色)和最小邊覆蓋(染色),\(Idea\)來源於消防局設立那道題。
對於最小點覆蓋,思考一個貪心,我們如果從底向上找點進行染色,那麼我們一定想要找到的是深度小的點,因為它永遠不會更差。所以說,我們考慮先按深度從大到小排一遍序,然後從頭掃一遍所有的點。如果從他到他的\(R\)級祖先有被染色的,那麼就不需要考慮;否則我們講其\(R\)級祖先染色,然後用\(R\)級祖先向根節點方向染色。
對於最小邊覆蓋,在這裡我要向我機房的同僚們鄭重地道歉——當時我眉飛色舞地講的\(std\),他是錯的。之所以當時講“不用向上傳遞”,原因是Luogu上有一道題,也是邊覆蓋(\(R = 1\)
那麼對於最小邊覆蓋,我們要做得其實很簡單,只需要把邊轉移到深度較大的節點上,做點覆蓋 即可。別忘了特判根節點是不應該算在內的。並且向上傳遞的時候,不應該算\(R\)級祖先——因為我們的邊是存在深度大的節點上的。
那麼就做完了,程式碼細節大概就是我通過記錄離點\(u\)最近的、染完色的點與\(u\)的距離。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define min Min
#define MAX 20010
#define Inf 19260817
using namespace std ;
struct Edge{
int to, next ;
}E[MAX] ; int cnt, head[MAX] ;
int R, i, j, FF, LastF, A, B ; char Mark ;
int Ans, N, M, F[MAX], dep[MAX], T[MAX], dist[MAX] ;
inline bool Compare(int A, int B){ return dep[A] > dep[B] ;}
inline int Min(int a, int b) {return a & ((a - b) >> 31) | b & (~ (a - b) >> 31) ;}
inline void _Add(int u, int v){
E[++ cnt].to = v, E[cnt].next = head[u], head[u] = cnt ;
E[++ cnt].to = u, E[cnt].next = head[v], head[v] = cnt ;
}
inline void Build(int now, int f){
F[now] = f, dep[now] = dep[f] + 1 ;
for (int k = head[now] ; k ; k = E[k].next)
if (E[k].to == f) continue ; else Build(E[k].to, now) ;
}
inline void Init(){
scanf("%d%d", &N, &R), Ans = 0 ;
memset(head, 0, sizeof(head)), cnt = 0 ;
for (i = 0 ; i <= N ; ++ i) T[i] = i, dist[i] = N ;
for (i = 1 ; i < N ; ++ i) scanf("%d%d", &A, &B), _Add(A, B) ;
Build(1, 0), sort(T + 1, T + N + 1, Compare) ;
}
int main(){
scanf("%d", &M) ;
while(M --){
cin >> Mark ; Init() ;
if (Mark == 'A'){
for (i = 1 ; i <= N ; ++ i){
FF = F[T[i]] ;
for (j = 1 ; j <= R ; ++ j)
dist[T[i]] = min(dist[T[i]], dist[FF] + j), LastF = FF, FF = F[FF] ;
FF = LastF ; if (dist[T[i]] <= R) continue ;
dist[FF] = 0, ++ Ans ; for (j = 0 ; j <= R ; ++ j) dist[FF] = j, FF = F[FF] ;
}
printf("%d\n", Ans) ;
}
else {
for (i = 1 ; i <= N ; ++ i){
if (T[i] == 1) continue ;
FF = F[T[i]] ;
for (j = 1 ; j <= R ; ++ j)
dist[T[i]] = min(dist[T[i]], dist[FF] + j), LastF = FF, FF = F[FF] ;
FF = LastF ; if (dist[T[i]] <= R) continue ; dist[FF] = 0 ;
for (j = 0 ; j < R ; ++ j) dist[FF] = j, FF = F[FF] ; ++ Ans ;//此處與點覆蓋有區別
}
printf("%d\n", Ans) ;
}
}
return 0 ;
}
\(T3\)
大概在這裡吧:\(Link\)
\(\rm{Code}\)
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXB 2010
#define MAXD 5010
#define MAXN 1000010
#define MAXC 6001000
#define Inf 1e17
#define LL long long
char Mark ;
using namespace std ;
namespace pksA{
#define ls(rt) rt << 1
#define rs(rt) rt << 1 | 1
#define Mid ((L + R) >> 1)
struct Tree{
LL M[2] ;
Tree(){M[0] = M[1] = Inf ;}
}T[MAXN << 2] ; int N, Len, rank[MAXN] ;
LL base[MAXN], t[MAXN], i, j, k, dp[MAXN] ;
template<class T> inline void Make_min(T &x, T &y){ x > y ? x = y : x = x ; }
inline LL Min(LL A, LL B){ return A & ((A - B) >> 63) | B & (~(A - B) >> 63) ;}
inline void push_up(int rt){
T[rt].M[0] = Min(T[ls(rt)].M[0], T[rs(rt)].M[0]) ;
T[rt].M[1] = Min(T[ls(rt)].M[1], T[rs(rt)].M[1]) ;
}
inline void update(int rt, int L, int R, int pos, LL M0, LL M1){ //BIT Insert
if (L == R){
Make_min(T[rt].M[0], M0) ;
Make_min(T[rt].M[1], M1) ;
return ;
}
if (pos <= Mid) update(ls(rt), L, Mid, pos, M0, M1) ;
else update(rs(rt), Mid + 1, R, pos, M0, M1) ; push_up(rt) ;
}
inline LL query(int rt, int L, int R, int ql, int qr, bool Mark){
if (ql > qr) return Inf ;
if (ql <= L && R <= qr) return T[rt].M[Mark] ;
LL res = Inf ;
if (ql <= Mid) res = Min(res, query(ls(rt), L, Mid, ql, qr, Mark)) ;
if (qr > Mid) res = Min(res, query(rs(rt), Mid + 1, R, ql ,qr, Mark)) ;
return res ;
}
void SolveA(){
cin >> N ; dp[1] = Inf ; rank[N + 1] = 0x3f ;
for (i = 1 ; i <= N ; ++ i)
scanf("%lld", &base[i]), t[i] = base[i] ;
sort(t + 1, t + N + 1) ;//discretization
Len = unique(t + 1, t + N + 1) - t - 1 ;
for (i = 1 ; i <= N ; ++ i)
rank[i] = lower_bound(t + 1, t + Len + 1, base[i]) - t ;
for (i = 2 ; i <= N ; ++ i){//dp
update(1, 1, Len, rank[i - 1], dp[i - 2] - base[i - 1], dp[i - 2] + base[i - 1]) ;
dp[i] = Min(query(1, 1, Len, 1, rank[i], 0) + base[i], query(1, 1, Len, rank[i] + 1, Len, 1) - base[i]) ;
}
cout << dp[N] << endl ; // by Flower_pks
}
}
namespace pksB{
stack <int> s ;
int N, Len, L[11] ;
int i, j, k, di, dj ;
int temp[MAXB][MAXB] ;
char S[MAXB], M[11][MAXB] ;
int Ans, dp[MAXB][MAXB], T ;
void SolveB(){
cin >> (S + 1), cin >> N, Len = strlen(S + 1) ;
for (i = 1 ; i <= N ; ++ i) cin >> (M[i] + 1), L[i] = strlen(M[i] + 1) ;
for (i = 1 ; i <= N ; ++ i){
memset(dp, 0, sizeof(dp)) ;
for (j = 1 ; j <= Len ; ++ j)
for (k = 1 ; k <= L[i] ; ++ k)
if (M[i][k] == S[j]) dp[j][k] = dp[j - 1][k - 1] + 1 ;
else dp[j][k] = max(dp[j - 1][k], dp[j][k - 1]) ;
if (Ans < dp[Len][L[i]]){
Ans = dp[Len][L[i]], T = i ;
for (di = 1 ; di <= Len ; ++ di)
for (j = 1 ; j <= L[i] ; ++ j)
temp[di][j] = dp[di][j] ;
}
}
for (i = Len ; i >= 1 ; -- i){
if (s.size() == Ans) break ;
for (j = L[T] ; j >= 1 ; -- j)
if (temp[i][j] != temp[i - 1][j] && temp[i][j] != temp[i - 1][j]){
s.push(i) ; break ;
}
}
cout << Ans << endl ; while (!s.empty()) printf("%c", S[s.top()]), s.pop() ;
}
}
namespace pksC{
#define Mod 998244853
int N, M, i, j, k ;
LL Sum[MAXC], F[MAXC] ;
void SolveC(){
scanf("%d%d", &N, &M) ;
Sum[0] = F[0] = M + 1 ;
for (i = 1 ; i <= N ; ++ i)
F[i] = (Sum[i - 1] + M + 1) % Mod,
Sum[i] = (Sum[i - 1] + F[i]) % Mod;
printf("%lld", F[N]) ;
}
#undef Mod
}
namespace pksD{
#undef Inf
#define Inf 1e30
int i, j, k ;
struct Nodes{
double x, y ;
}base[MAXD << 1] ;
int N ; double dp[MAXD][MAXD], Ans ;
inline bool Compare(Nodes A, Nodes B){
return A.x < B.x ;
}
inline double dis(int x, int y){
return sqrt((base[x].x - base[y].x) * (base[x].x - base[y].x)
+ (base[x].y - base[y].y) * (base[x].y - base[y].y)) ;
}
void SolveD(){
cin >> N ;
for (i = 1 ; i <= N ; ++ i)
scanf("%lf%lf", &base[i].x, &base[i].y) ;
sort(base + 1, base + N + 1, Compare) ;
for (i = 1 ; i <= N ; ++ i)
for (j = 1 ; j <= N ; ++ j)
dp[i][j] = Inf * Inf ; Ans = Inf * Inf ;
dp[1][2] = dis(1, 2) ;
for (i = 1 ; i < N ; ++ i)
for (j = i + 1 ; j <= N ; ++ j)
dp[i][j + 1] = min(dp[i][j + 1], dp[i][j] + dis(j, j + 1)),
dp[j][j + 1] = min(dp[j][j + 1], dp[i][j] + dis(i, j + 1)) ;
for(i = 1 ; i < N ; ++ i)
Ans = min(Ans, dp[i][N] + dis(i, N));
printf("%.2lf", Ans) ;
}
}
int main(){
cin >> Mark ;
if (Mark == 'A') pksA :: SolveA() ;
else if (Mark == 'B') pksB :: SolveB() ;
else if (Mark == 'C') pksC :: SolveC() ;
else pksD :: SolveD() ; return 0 ;
}