杂七杂八的题目。
有 n n n n n n  
设第 i i i A i A_i A i  
对于任意 i ∈ [ 2 , n ] i \in [2, n] i ∈ [ 2 , n ] A i − 1 ≤ A i A_{i-1} \leq A_{i} A i − 1  ≤ A i   
对于任意 i ∈ [ 1 , n ] i \in [1, n] i ∈ [ 1 , n ] 1 ≤ A i ≤ n 1 \leq A_{i} \leq n 1 ≤ A i  ≤ n  
对于任意一个大小为 k k k 1 ≤ k < n 1 \leq k < n 1 ≤ k < n S S S k + 1 k+1 k + 1 T T T ∑ x ∈ S A x < ∑ x ∈ T A x \sum_{x \in S}A_x < \sum_{x\in T}A_x ∑ x ∈ S  A x  < ∑ x ∈ T  A x   
 
 
你需要计算,有多少种给题目赋分的方案,使得能满足上述三个条件。请求出答案对 M M M  
 
2   ≤   N   ≤   5000 2\ \leq\ N\ \leq\ 5000 2   ≤   N   ≤   5 0 0 0 
妙,实在是太妙了。
首先对于给定的 k k k S S S A A A k k k T T T A A A k + 1 k+1 k + 1 k k k k = ⌊ n − 1 2 ⌋ k = \lfloor \frac{n-1}{2} \rfloor k = ⌊ 2 n − 1  ⌋ 
考虑维护 ∑ x ∈ T A x − ∑ x ∈ S A x \sum_{x \in T} A_x - \sum_{x \in S} A_x ∑ x ∈ T  A x  − ∑ x ∈ S  A x  A A A n n n 1 1 1 
现在还有一个问题就是减 1 1 1 n n n n n n 1 1 1 0 0 0 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include  <bits/stdc++.h>  using  namespace  std;#define  N 5005 int  n,P,ans,w[N],dp[N];int  main () 	scanf ("%d %d" ,&n,&P);dp[n]=1 ; 	for (int  i=1 ;i<=(n+1 )/2 ;++i) w[i]=i; 	for (int  i=1 ;i<=n/2 ;++i) w[n-i+1 ]=i; 	for (int  i=1 ;i<=n;++i) for (int  j=n;j>=w[i];--j) 		dp[j-w[i]]=(dp[j-w[i]]+dp[j])%P; 	for (int  i=1 ;i<=n;++i) ans=(ans+dp[i])%P; 	printf ("%d\n" ,ans);return  0 ; } 
 
给定两棵树 S , T S,T S , T S S S T T T 
1 ≤ ∣ S ∣ ≤ 1000 1 \le |S| \le 1000 1 ≤ ∣ S ∣ ≤ 1 0 0 0 1 ≤ ∣ T ∣ ≤ 12 1 \le |T| \le 12 1 ≤ ∣ T ∣ ≤ 1 2 
首先我们可以枚举一下 T T T S S S T T T 
下面就可以类似 d f s dfs d f s S ( i , j ) S(i,j) S ( i , j ) S S S i i i T T T j j j 
设 s o n son s o n T T T j j j j j j S S S s o n son s o n 2 ∣ T ∣ 2^{|T|} 2 ∣ T ∣ 
复杂度 O ( ∣ S ∣ 2 ∣ T ∣ 2 ∣ T ∣ ) O(|S|^2|T|2^{|T|}) O ( ∣ S ∣ 2 ∣ T ∣ 2 ∣ T ∣ ) 
 点击查看代码  
 
给定 n , m n,m n , m n n n m m m i i i b i b_i b i  i i i a i a_i a i  
现在进行一场游戏,Bob 是本场游戏的玩家,而 Alice 则是场景布置者,Alice 可以给每个宝箱上一些锁(第 j j j j j j 
如果 Bob 可以购买一些钥匙,然后打开一些宝箱,使得 Bob 的收益大于 0 0 0 
现在 Alice 打算布置宝箱上的锁,第 i i i j j j c i , j c_{i,j} c i , j  
n , m ≤ 6 , a i , b i ≤ 4 , c i , j ≤ 1 0 7 n,m\le 6,a_i,b_i\le 4,c_{i,j}\le 10^7 n , m ≤ 6 , a i  , b i  ≤ 4 , c i , j  ≤ 1 0 7 
特别的,一个箱子上可以放置若干把锁,Bob 需打开所有锁才能获得内部的钱。
考虑如果已知了一种布置锁的方案,我们能不能判断胜负。
其实这个是可以的,因为一种方案 Alice 能获胜当且仅当 Bob 无论选择开启哪些宝箱得到的收益都不够,也就是如果宝箱 i i i j j j ( i , j ) (i,j) ( i , j ) N ( S ) N(S) N ( S ) S S S 
∀ S ⊆ [ 1 , n ] , ∑ x ∈ S a x ≤ ∑ x ∈ N ( S ) b x \forall S\subseteq [1,n],\sum_{x \in S} a_x \le \sum_{x \in N(S)} b_x
 ∀ S ⊆ [ 1 , n ] , x ∈ S ∑  a x  ≤ x ∈ N ( S ) ∑  b x  
这东西就是一个 hall 定理的形式,也就是说我们可以将宝箱 i i i a i a_i a i  j j j b j b_j b j  
在完美匹配的情况下必然是宝箱对应的点完全匹配没了,钥匙对应的点可能有剩下的,所以我们可以依次考虑每一个宝箱对应的 a i a_i a i  i i i i − 1 i-1 i − 1 b b b b i ≤ 4 b_i \le 4 b i  ≤ 4 
也就是设 d p [ i ] [ S ] dp[i][S] d p [ i ] [ S ] i i i b b b S S S O ( n 5 2 m ) O(n5^{2m}) O ( n 5 2 m ) 
考虑优化,这种题优化最常见的就是分步,我们不一次决定所有的连边情况,而一次只决定与一个钥匙的连边情况,虽然这样可能出现与同一个钥匙连边多次导致贡献被重复计算多次,但是这一定不优,所以这样得到的答案也是对的。
也就是设 d p [ i ] [ S ] [ j ] dp[i][S][j] d p [ i ] [ S ] [ j ] i i i b b b S S S a i a_i a i  j j j n , m n,m n , m O ( 16 n 2 5 n ) O(16n^25^{n}) O ( 1 6 n 2 5 n ) 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <bits/stdc++.h>  #define  int long long using  namespace  std;int  n,m,a[100 ],b[100 ],c[100 ][100 ],f[8 ][20000 ][8 ],p[20000 ][8 ],pw[10 ];void  get (int  S) 	int  tS = S; 	for (int  i=1 ; i<=m; i++){ 		p[S][i] = tS % 5 ; 		tS /= 5 ; 	} } void  chkmin (int  &a,int  b) 	a = min (a,b); } signed  main () 	scanf ("%lld%lld" ,&n,&m); 	for (int  i=1 ; i<=n; i++)	scanf ("%lld" ,&a[i]); 	for (int  i=1 ; i<=m; i++)	scanf ("%lld" ,&b[i]); 	for (int  i=1 ; i<=n; i++){ 		for (int  j=1 ; j<=m; j++){ 			scanf ("%lld" ,&c[i][j]); 		} 	} 	pw[1 ] = 1 ; 	for (int  i=2 ; i<=m; i++)	pw[i] = pw[i-1 ] * 5 ; 	int  mx = 0 ; 	for (int  i=1 ; i<=m; i++)	mx += pw[i] * b[i]; 	for (int  i=0 ; i<=mx; i++)	get (i); 	memset (f,0x3f ,sizeof (f)); 	int  inf = f[0 ][0 ][0 ]; 	f[1 ][mx][a[1 ]] = 0 ;  	for (int  i=1 ; i<=n; i++){ 		for (int  j=mx; j>=0 ; j--){ 			for (int  k=a[i]; k>=0 ; k--){ 				if (f[i][j][k] == inf)	continue ; 				for (int  h=1 ; h<=m; h++){ 					for (int  g=1 ; g<=p[j][h] && g <= k; g++){ 						chkmin (f[i][j-g*pw[h]][k-g],f[i][j][k]+c[i][h]); 					} 				} 			} 			chkmin (f[i+1 ][j][a[i+1 ]],f[i][j][0 ]); 		} 	} 	int  ans = inf; 	for (int  i=0 ; i<=mx; i++)	chkmin (ans,f[n+1 ][i][0 ]); 	if (ans == inf)	printf ("-1\n" ); 	else 	printf ("%lld\n" ,ans); 	return  0 ; } 
 
已知两个无限长的等差数列,首项分别为 b 1 , b 2 b_1, b_2 b 1  , b 2  a 1 , a 2 a_1, a_2 a 1  , a 2  [ L , R ] [L,R] [ L , R ] 
只要我们可以找到某一个数 p p p p p p p + k × lcm ( a 1 , a 2 ) p + k\times \textup{lcm}(a_1,a_2) p + k × lcm ( a 1  , a 2  ) 
而找到数 p p p 
b 1 + a 1 x = b 2 + a 2 y b_1 + a_1 x = b_2 + a_2 y
 b 1  + a 1  x = b 2  + a 2  y 
这个东西移项之后就是一个 A x + B y = C Ax + By = C A x + B y = C p = b 1 + a 1 x p = b_1 + a_1 x p = b 1  + a 1  x 
假设我们找到了数 p p p [ L − p , R − p ] [L-p,R-p] [ L − p , R − p ] lcm ( a 1 , a 2 ) \textup{lcm}(a_1,a_2) lcm ( a 1  , a 2  ) p p p L − p L-p L − p R − p R-p R − p 
比较好做的方法就是让 p p p lcm ( a 1 , a 2 ) \textup{lcm}(a_1,a_2) lcm ( a 1  , a 2  ) 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <bits/stdc++.h>  #define  int __int128 using  namespace  std;inline  int  read ()     int  x=0 ,w=1 ;     char  ch=getchar ();     for (;ch>'9' ||ch<'0' ;ch=getchar ()) if (ch=='-' ) w=-1 ;     for (;ch>='0' &&ch<='9' ;ch=getchar ()) x=x*10 +ch-'0' ;     return  x*w; } inline  void  write (int  x)     if (x<0 ) putchar ('-' ),x=-x;     if (x>9 ) write (x/10 );     putchar (x%10 +'0' ); } void  exgcd (int  a,int  b,int  &x,int  &y) 	if (b == 0 ){ 		x = 1 ,y = 0 ; 		return ; 	} 	exgcd (b,a%b,x,y); 	int  xx = x,yy = y; 	x = yy; 	y = xx - (a / b) * yy; } int  get (int  x,int  y) 	if (x < 0 )	return  0 ; 	return  x / y + 1 ; } signed  main () 	int  a1,b1,a2,b2,L,R; 	a1 = read (),b1 = read (),a2 = read (),b2 = read (),L = read (),R = read (); 	L = max (L,max (b1,b2)); 	int  A = a1,B = -a2,C = b2 - b1; 	if (C % __gcd(A,B) != 0 ){ 		printf ("0\n" ); 		return  0 ; 	} 	int  x,y;exgcd (A,B,x,y); 	x *= C/__gcd(A,B); 	int  mn = b1 + a1 * x,len = a1 / __gcd(a1,a2) * a2; 	while (L - mn <= 0 ){ 		mn -= len; 	} 	L -= mn,R -= mn; 	if (L > R){ 		printf ("0\n" ); 	} 	else { 		write (get (R,len) - get (L-1 ,len)); 	} 	return  0 ; } 
 
n n n m m m m m m 
1 ≤ n , m ≤ 5000 1 \le n,m \le 5000 1 ≤ n , m ≤ 5 0 0 0 
显然要先将老鼠和洞按照坐标从小到大排序。
首先必然是更靠前的老鼠占据更靠前的洞,也就是说必然是一个前缀的老鼠占据一个前缀的洞,且以后的老鼠不会再占据这个前缀的洞了。
进一步观察对于每一个洞,进这个洞的老鼠必然是某一个区间里的所有老鼠。
所以就可以设 d p [ i ] [ j ] dp[i][j] d p [ i ] [ j ] i i i j j j S ( i , j ) S(i,j) S ( i , j ) j j j i i i 
d p [ i ] [ j ] = min  0 ≤ k ≤ c i ( d p [ i − 1 ] [ j − k ] + S ( i , j ) − S ( i , j − k ) ) dp[i][j] = \min_{0 \le k \le c_i} (dp[i-1][j-k] + S(i,j) - S(i,j-k))
 d p [ i ] [ j ] = 0 ≤ k ≤ c i  min  ( d p [ i − 1 ] [ j − k ] + S ( i , j ) − S ( i , j − k ) ) 
从 d p [ i − 1 ] dp[i-1] d p [ i − 1 ] d p [ i ] dp[i] d p [ i ] min  \min min O ( n m ) O(nm) O ( n m ) 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <bits/stdc++.h>  #define  int long long using  namespace  std;const  int  N = 5005 ;struct  node {	int  x,c; }p[N]; int  dp[2 ][N],s[N],x[N];bool  cmp (node a,node b) 	return  a.x < b.x; } signed  main () 	int  n,m;scanf ("%lld%lld" ,&n,&m); 	for (int  i=1 ; i<=n; i++)	scanf ("%lld" ,&x[i]); 	sort (x+1 ,x+n+1 ); 	for (int  i=1 ; i<=m; i++)	scanf ("%lld%lld" ,&p[i].x,&p[i].c); 	sort (p+1 ,p+m+1 ,cmp); 	memset (dp,0x3f ,sizeof (dp)); 	dp[0 ][0 ] = 0 ; 	for (int  i=1 ; i<=m; i++){ 		int  now = i & 1 ,lst = now ^ 1 ; 		memset (dp[now],0x3f ,sizeof (dp[now])); 		s[0 ] = 1 ; 		for (int  j=1 ; j<=n; j++)	s[j] = s[j-1 ] + abs (x[j] - p[i].x); 		deque<int > q; 		for (int  j=0 ; j<=n; j++){ 			while (!q.empty () && dp[lst][q.back ()]-s[q.back ()] > dp[lst][j] - s[j])	q.pop_back (); 			q.push_back (j); 			while (!q.empty () && q.front () < j-p[i].c)	q.pop_front (); 			dp[now][j] = dp[lst][q.front ()]-s[q.front ()]+s[j]; 		} 	} 	 	if (dp[m&1 ][n] > 1ll  * 1e17 )	printf ("-1\n" ); 	else 	printf ("%lld\n" ,dp[m&1 ][n]); 	return  0 ; } 
 
小 R 想为小 H 写一首情诗。他现在想出了 n n n 1 , 2 … n 1, 2 \dots n 1 , 2 … n n n n 1 ∼ n 1 \sim n 1 ∼ n p 1 , p 2 … p n p_1, p_2\dots p_n p 1  , p 2  … p n  i i i p i p_i p i  p i p_i p i  
不过,由于小 R 是位 OIer,所以他的文采并不是很稳定。他实际上会严重高估自己诗句的优美程度。若一条诗句在小 R 眼里的优美度为 x x x x x x 1 1 1 1 1 1 2 2 2 f ( x ) f(x) f ( x ) 1 + log  2 lowbit  ( x ) 1 + \log_2 \operatorname{lowbit}(x) 1 + log  2  l o w b i t ( x ) 
小 R 知道,小 H 拿到诗后,只会选取诗的一段来看,而她感受到的优美度是所有她读到的诗句之和。具体的,若诗有 n n n [ 1 , n ] [1, n] [ 1 , n ] > 0 > 0 > 0 [ l , r ] [l, r] [ l , r ] ∑ l ≤ i ≤ r f ( p i ) \displaystyle\sum_{l \leq i \leq r}f(p_i) l ≤ i ≤ r ∑  f ( p i  ) 所有情况下小 H 感受到的优美度之和 。
照理来说,总优美度最大的组合方式必然是最好的。遗憾的是,在小 R 的精密计算下,他发现,只有他选择总优美度恰好为 第 k k k   的情诗时,他才最有可能和小 H 走到一起。于是,小 R 想要知道,对于 n ! n! n ! k k k p 1 … p n p_1 \dots p_n p 1  … p n  
小 R 发现这是一个 NPC 问题,他只好来向你求助了。由于总优美度过于巨大,你只需要帮他求出答案对 998244353 998244353 9 9 8 2 4 4 3 5 3 
特别的,小 R 写了 q q q q q q 
对于 100 % 100\% 1 0 0 % 1 ≤ n ≤ 1 0 18 1 \leq n \leq 10^{18} 1 ≤ n ≤ 1 0 1 8 1 ≤ k ≤ min  ( 1 0 18 , n ! ) 1 \leq k \leq \min(10^{18}, n!) 1 ≤ k ≤ min ( 1 0 1 8 , n ! ) 1 ≤ q ≤ 10 1 \leq q\le 10 1 ≤ q ≤ 1 0 
不理解这个题为什么评为 省选/NOI−。
首先因为我们算贡献是只在意每一个数的 lowbit \textup{lowbit} lowbit x x x 1 + log  2 lowbit ( x ) 1 + \log_2 \textup{lowbit}(x) 1 + log  2  lowbit ( x ) 
这样的话就会发现,对于一个转化后的序列其实是对应很多个转化前的序列的,设 c n t i cnt_i c n t i  1 + log  2 lowbit ( x ) = i 1 + \log_2 \textup{lowbit}(x) = i 1 + log  2  lowbit ( x ) = i ∏ c n t i ! \prod cnt_i! ∏ c n t i  ! 
打个表就会发现当 n ≥ 30 n \ge 30 n ≥ 3 0 1 0 18 10^{18} 1 0 1 8 
显然如果数 x x x i i i x × i × ( n − i + 1 ) x \times i \times (n-i+1) x × i × ( n − i + 1 ) c n t i cnt_i c n t i  
∑ i = 1 n i × ( n − i + 1 ) = ( n + 1 ) ∑ i = 1 n i − ∑ i = 1 n i 2 = n ( n + 1 ) 2 2 − n ( n + 1 ) ( 2 n + 1 ) 6 \sum_{i=1}^n i \times (n-i+1) =  (n+1) \sum_{i=1}^n i - \sum_{i=1}^n i^2 = \frac{n(n+1)^2}{2} - \frac{n(n+1)(2n+1)}{6}
 i = 1 ∑ n  i × ( n − i + 1 ) = ( n + 1 ) i = 1 ∑ n  i − i = 1 ∑ n  i 2 = 2 n ( n + 1 ) 2  − 6 n ( n + 1 ) ( 2 n + 1 )  
所以我们就可以以 O ( log  n ) O(\log n) O ( log  n ) 
对于 n ≤ 29 n \le 29 n ≤ 2 9 1 0 4 10^4 1 0 4 d p dp d p 
设 d p [ a ] [ b ] [ c ] [ d ] [ e ] [ v ] dp[a][b][c][d][e][v] d p [ a ] [ b ] [ c ] [ d ] [ e ] [ v ] 1 , 2 , 3 , 4 , 5 1,2,3,4,5 1 , 2 , 3 , 4 , 5 a , b , c , d , e a,b,c,d,e a , b , c , d , e v v v n = 29 n = 29 n = 2 9 3 × 1 0 7 3 \times 10^7 3 × 1 0 7 O ( 1 ) O(1) O ( 1 ) 
现在还有一个问题就是如何计算 c n t i cnt_i c n t i  lowbit = 2 i \textup{lowbit} = 2^i lowbit = 2 i i i i 2 i 2^i 2 i 0 0 0 
c n t i = ⌈ ⌊ n 2 i − 1 ⌋ 2 ⌉ cnt_i = \left\lceil \frac{\lfloor \frac{n}{2^{i-1}} \rfloor}{2} \right\rceil
 c n t i  = ⌈ 2 ⌊ 2 i − 1 n  ⌋  ⌉ 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 #include <bits/stdc++.h>  #define  int long long using  namespace  std;const  int  N = 1e6 +5 ;const  int  MOD = 998244353 ;int  n,k,cnt[N],pw[N];int  lowbit (int  x) 	return  x & (-x); } int  power (int  a,int  b) 	int  res = 1 ; 	while (b){ 		if (b & 1 )	res = res * a % MOD; 		a = a * a % MOD; 		b >>= 1 ; 	} 	return  res; } int  get1 (int  r) 	r %= MOD; 	return  r * (r + 1 )%MOD * power (2 ,MOD-2 )%MOD; } int  get2 (int  r) 	r %= MOD; 	return  r * (r + 1 )%MOD * (2  * r + 1 )%MOD * power (6 ,MOD-2 )%MOD; } int  get (int  n,int  l,int  r) 	return  ((n+1 )%MOD * (get1 (r) - get1 (l-1 ) + MOD) % MOD - (get2 (r) - get2 (l-1 ))%MOD + MOD)%MOD; } void  add (int  &a,int  b) 	a = (a + b) % MOD; } namespace  brute{	int  tot[N],sum,val[N],fac[N]; 	int  f[16 ][9 ][5 ][3 ][2 ][11005 ]; 	void  dfs (int  now)  		if (now == n + 1 ){ 			tot[sum]++; 			return ; 		} 		for (int  i=1 ; i<=6 ; i++){ 			if (cnt[i]){ 				cnt[i]--; 				sum += i * val[now]; 				dfs (now+1 ); 				sum -= i * val[now]; 				cnt[i]++; 			} 		} 	} 	void  work ()  		f[0 ][0 ][0 ][0 ][0 ][0 ] = 1 ; 		for (int  a=0 ; a<=cnt[1 ]; a++){ 			for (int  b=0 ; b<=cnt[2 ]; b++){ 				for (int  c=0 ; c<=cnt[3 ]; c++){ 					for (int  d=0 ; d<=cnt[4 ]; d++){ 						for (int  e=0 ; e<=cnt[5 ]; e++){ 							for (int  val=0 ; val<=11000 ; val++){ 								if (!f[a][b][c][d][e][val])	continue ; 								int  pos = a + b + c + d + e + 1 ; 								if (a != cnt[1 ])	add (f[a+1 ][b][c][d][e][val+pos*(n-pos+1 )],f[a][b][c][d][e][val]); 								if (b != cnt[2 ])	add (f[a][b+1 ][c][d][e][val+2 *pos*(n-pos+1 )],f[a][b][c][d][e][val]); 								if (c != cnt[3 ])	add (f[a][b][c+1 ][d][e][val+3 *pos*(n-pos+1 )],f[a][b][c][d][e][val]); 								if (d != cnt[4 ])	add (f[a][b][c][d+1 ][e][val+4 *pos*(n-pos+1 )],f[a][b][c][d][e][val]); 								if (e != cnt[5 ])	add (f[a][b][c][d][e+1 ][val+5 *pos*(n-pos+1 )],f[a][b][c][d][e][val]); 							} 						} 					} 				} 			} 		} 		int  ans = 1 ; 		fac[0 ] = 1 ; 		for (int  i=1 ; i<=16 ; i++)	fac[i] = fac[i-1 ] * i; 		for (int  i=1 ; i<=5 ; i++)		ans = ans * fac[cnt[i]]; 		for (int  i=0 ; i<=10000 ; i++){ 			tot[i] = f[cnt[1 ]][cnt[2 ]][cnt[3 ]][cnt[4 ]][cnt[5 ]][i]; 			tot[i] += tot[i-1 ]; 			if (ans * tot[i] >= k){ 				printf ("%lld\n" ,i); 				break ; 			} 		}	 		for (int  a=0 ; a<=cnt[1 ]; a++){ 			for (int  b=0 ; b<=cnt[2 ]; b++){ 				for (int  c=0 ; c<=cnt[3 ]; c++){ 					for (int  d=0 ; d<=cnt[4 ]; d++){ 						for (int  e=0 ; e<=cnt[5 ]; e++){ 							for (int  val=0 ; val<=11000 ; val++){ 								f[a][b][c][d][e][val] = 0 ; 							} 						} 					} 				} 			} 		} 	} } signed  main () 	int  T;scanf ("%lld" ,&T); 	while (T--){ 		scanf ("%lld%lld" ,&n,&k); 		pw[0 ] = 1 ; 		for (int  i=1 ; i<=61 ; i++)	pw[i] = pw[i-1 ] * 2 ; 		for (int  i=1 ; i<=61 ; i++){ 			cnt[i] = (n / pw[i-1 ] + 1 ) / 2 ; 		} 		if (n <= 29 ){ 			brute::work (); 		} 		else { 			int  ans = 0 ; 			int  l = (cnt[1 ] + 1 ) / 2 ,r = cnt[1 ] / 2 ; 			ans = get (n,(n+1 )/2 -l+1 ,(n+1 )/2 +r); 			for (int  i=2 ; i<=61 ; i++){ 				if (!cnt[i])	continue ; 				if (l > r)	++r,add (ans,get (n,(n+1 )/2 +r,(n+1 )/2 +r)*i % MOD),--cnt[i]; 				if (!cnt[i])	continue ; 				int  L = (cnt[i] + 1 ) / 2 ,R = cnt[i] / 2 ; 				add (ans,(get (n,(n+1 )/2 -(l+L)+1 ,(n+1 )/2 +(r+R))-get (n,(n+1 )/2 -l+1 ,(n+1 )/2 +r)) * i % MOD); 				l += L;r += R; 			} 			printf ("%lld\n" ,(ans%MOD + MOD)%MOD); 		} 	} 	return  0 ; } 
 
Gena 非常想参加“俄罗斯code cup”的决赛,或是至少得到一件T恤。但是比赛的题目太复杂了,所以他安排他的 n n n 
在比赛中会有 m m m i i i x x x k k k b b b 
Gena 很节约用钱,所以他希望尽可能少的花钱去解决所有问题。请你帮助 Gena,告诉他怎样花费最少的钱。最初,Gena 的电脑没有连接任何显示器。
1 ≤ n ≤ 100 1 \le n \le 100 1 ≤ n ≤ 1 0 0 1 ≤ m ≤ 20 1 \le m \le 20 1 ≤ m ≤ 2 0 
如果我们可以确定连接多少台显示器,那么就类似一个背包问题就比较好做了。
注意到我们最优的连接显示器的数量必然恰好是某个人要求的显示器数量,所以只有 O ( n ) O(n) O ( n ) 
复杂度 O ( n 2 m ) O(n2^m) O ( n 2 m ) 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <bits/stdc++.h>  #define  int long long using  namespace  std;const  int  INF = 2e18 ;const  int  N = 1005 ;struct  node {	int  x,k,m,val; }a[N]; int  n,m,b,dp[2 ][1500005 ],ans;bool  cmp (node a,node b) 	return  a.k < b.k; } void  chkmin (int  &a,int  b) 	a = min (a,b); } signed  main () 	scanf ("%lld%lld%lld" ,&n,&m,&b); 	for (int  i=1 ; i<=n; i++){ 		scanf ("%lld%lld%lld" ,&a[i].x,&a[i].k,&a[i].m); 		a[i].val = 0 ; 		for (int  j=1 ; j<=a[i].m; j++){ 			int  p;scanf ("%lld" ,&p); 			a[i].val |= (1 <<(p-1 )); 		} 	} 	sort (a+1 ,a+n+1 ,cmp); 	memset (dp,0x3f ,sizeof (dp)); 	dp[0 ][0 ] = 0 ;ans = INF; 	for (int  i=0 ; i<n; i++){ 		int  now = i & 1 ,nxt = now ^ 1 ; 		memset (dp[nxt],0x3f ,sizeof (dp[nxt])); 		for (int  j=0 ; j<(1 <<m); j++){ 			chkmin (dp[nxt][j],dp[now][j]); 			chkmin (dp[nxt][j|a[i+1 ].val],dp[now][j]+a[i+1 ].x); 		} 		chkmin (ans,dp[now][(1 <<m)-1 ]+b*a[i].k); 	} 	chkmin (ans,dp[n&1 ][(1 <<m)-1 ]+b*a[n].k); 	if (ans == INF)	printf ("-1\n" ); 	else 	printf ("%lld\n" ,ans); 	return  0 ; } 
 
设 F F F [ l , r ] [l,r] [ l , r ] k k k a 1 . . . a k a_{1}...a_{k} a 1  . . . a k  gcd  ( F a 1 , F a 2 , . . . , F a k ) \gcd(F_{a_{1}},F_{a_{2}},...,F_{a_{k}}) g cd( F a 1   , F a 2   , . . . , F a k   ) m m m 
1 ≤ l ≤ r ≤ 1 0 12 1 \le l \le r \le 10^{12} 1 ≤ l ≤ r ≤ 1 0 1 2 
有一个很神奇的结论就是 gcd  ( F x , F y ) = F gcd  ( x , y ) \gcd(F_x,F_y) = F_{\gcd(x,y)} g cd( F x  , F y  ) = F g c d ( x , y )  k k k gcd  \gcd g cd
假设 gcd  = p \gcd = p g cd= p p p p k k k 
⌊ r p ⌋ − ⌊ l − 1 p ⌋ ≥ k \left\lfloor \frac{r}{p} \right\rfloor - \left\lfloor \frac{l-1}{p} \right\rfloor \ge k
 ⌊ p r  ⌋ − ⌊ p l − 1  ⌋ ≥ k 
所以可以考虑对于 r r r [ L , R ] [L,R] [ L , R ] p p p ⌊ l − 1 p ⌋ \left\lfloor \frac{l-1}{p} \right\rfloor ⌊ p l − 1  ⌋ p p p R R R 
然后这样我们就可以找到一个数 p o s pos p o s F p o s F_{pos} F p o s  F p o s F_{pos} F p o s  
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <bits/stdc++.h>  #define  int long long using  namespace  std;int  MOD;void  add (int  &a,int  b) 	a = (a + b) % MOD; } struct  Matrix {	int  n,m; 	int  a[2 ][2 ]; }; Matrix operator  * (Matrix a,Matrix b){ 	Matrix c; 	c.n = a.n,c.m = b.m; 	for (int  i=0 ; i<c.n; i++){ 		for (int  j=0 ; j<c.m; j++){ 			c.a[i][j] = 0 ; 			for (int  k=0 ; k<a.m; k++){ 				add (c.a[i][j],a.a[i][k] * b.a[k][j] % MOD); 			} 		} 	} 	return  c; } int  solve (int  pos) 	if (pos == 1  || pos == 2 )	return  1 ; 	Matrix a,f,res; 	a.n = 2 ,a.m = 2 ; 	a.a[0 ][0 ] = 0 ,a.a[0 ][1 ] = 1 ; 	a.a[1 ][0 ] = 1 ,a.a[1 ][1 ] = 1 ; 	f.n = 1 ,f.m = 2 ; 	f.a[0 ][0 ] = f.a[0 ][1 ] = 1 ; 	res.n = 2 ,res.m = 2 ; 	res.a[0 ][0 ] = 1 ,res.a[0 ][1 ] = 0 ; 	res.a[1 ][0 ] = 0 ,res.a[1 ][1 ] = 1 ; 	int  b = pos - 2 ; 	while (b){ 		if (b & 1 )	res = res * a; 		a = a * a; 		b >>= 1 ; 	} 	return  (f * res).a[0 ][1 ]; } signed  main () 	int  l,r,k;scanf ("%lld%lld%lld%lld" ,&MOD,&l,&r,&k); 	int  ans = 1 ; 	for (int  L=1 ,R; L<=r; L=R+1 ){ 		R = r / (r / L); 		if (r / R - (l-1 ) / R >= k)	ans = R; 	} 	printf ("%lld\n" ,solve (ans) % MOD); 	return  0 ; } 
 
你是一位骑士,与其他 n − 1 n-1 n − 1 
幸运的是你知道任意骑士 i i i j j j 
你非常渴望取得胜利,想知道自己得到 LKJ 的最大概率是多少,注意你是 1 1 1 
1 ≤ n ≤ 18 1 \le n \le 18 1 ≤ n ≤ 1 8 
感觉上就是需要 d p dp d p d p [ i ] [ S ] dp[i][S] d p [ i ] [ S ] S S S i i i 
注意到我们的转移其实类似博弈的过程,也就是我们会选择一个后继里面最优的状态,然后转移到这个状态,所以上文的某些信息就可以理解为最后 1 1 1 
直接做复杂度就是 O ( n 2 2 n ) O(n^22^n) O ( n 2 2 n ) 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <bits/stdc++.h>  using  namespace  std;const  int  N = 19 ;double  p[N][N];double  dp[1 <<19 ][N];void  chkmax (double  &a,double  b) 	a = max (a,b); } int  main () 	int  n;scanf ("%d" ,&n); 	for (int  i=1 ; i<=n; i++){ 		for (int  j=1 ; j<=n; j++){ 			scanf ("%lf" ,&p[i][j]); 		} 		p[i][0 ] = 1 ; 	} 	dp[(1 <<n)-1 ][1 ] = 1 ; 	for (int  S=(1 <<n)-1 ; S>=0 ; S--){ 		for (int  i=0 ; i<=n; i++){ 			if (S != 0  && i == 0 )	continue ; 			for (int  j=1 ; j<=n; j++){ 				if ((S>>(j-1 )) & 1 )	continue ; 				chkmax (dp[S][i],p[i][j]*dp[S|(1 <<(j-1 ))][i]+p[j][i]*dp[S|(1 <<(j-1 ))][j]); 			} 		} 	} 	printf ("%.7f\n" ,dp[0 ][0 ]); 	return  0 ; } 
 
小 Biu 最近喜欢上一款角色扮演游戏,游戏中的每一款武器有 k k k a 1 , . . . , a k a_{1},...,a_{k} a 1  , . . . , a k  
游戏中的主角为英雄,英雄发起攻击时,造成的伤害不仅与武器有关,还与英雄的力量有关。如果英雄的力量为 n n n [ 1 , n ] [1,n] [ 1 , n ] 
现在小 Biu 获得了一把新的武器装备,他想知道用某个英雄发起攻击时,造成的伤害值为多少。
1 ≤ n ≤ 1 0 13 1 \le n \le 10^{13} 1 ≤ n ≤ 1 0 1 3 1 ≤ k ≤ 100 1 \le k \le 100 1 ≤ k ≤ 1 0 0 1 ≤ a i ≤ 1000 1 \le a_i \le 1000 1 ≤ a i  ≤ 1 0 0 0 
复杂度比较玄学,但是的确跑得很快。
一个感觉就是暴力可以过,因为我们最多选 15 15 1 5 1 0 13 10^{13} 1 0 1 3 
也就是对于选奇数个数的情况为负贡献,对于选偶数个数的情况为正贡献,因为 ⌊ ⌊ a b ⌋ c ⌋ = ⌊ a b × c ⌋ \lfloor \frac{\lfloor \frac{a}{b} \rfloor}{c} \rfloor = \lfloor \frac{a}{b \times c} \rfloor ⌊ c ⌊ b a  ⌋  ⌋ = ⌊ b × c a  ⌋ n n n ⌊ n a ⌋ \lfloor \frac{n}{a} \rfloor ⌊ a n  ⌋ 
将数按从大到小的顺序排序,然后对于 n n n 
 点击查看代码  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include  <bits/stdc++.h>  using  namespace  std;#define  int long long int  n, k, a[110 ], f[102 ][300010 ];int  dfs (int  now, int  x)  	if  (now > k) return  x; 	if  (x > 300000 ) 		return  dfs (now + 1 , x) - dfs (now + 1 , x / a[now]); 	if  (~f[now][x]) return  f[now][x]; 	return  f[now][x] = dfs (now + 1 , x) - dfs (now + 1 , x / a[now]); } signed  main ()  	memset (f, -1 , sizeof (f)); 	cin >> n >> k; 	for  (int  i = 1 ; i <= k; i++) 		cin >> a[i]; 	sort (a + 1 , a + k + 1 , greater <int >()); 	cout << dfs (1 , n) << endl; 	return  0 ; }