数论分块练习([CF830 C]Bamboo Partition + [hdu 6395]Sequence )

CSDN日常打广告

T1:Sequence

title

传送

solution

一眼就是很裸的矩阵加速
\(\lfloor\frac{p}{l}\rfloor\)分块矩阵加速就可以了

\[\begin{bmatrix} B\\ A\\ 1\\ \end{bmatrix} \times \begin{bmatrix} D&C&\lfloor\frac{p}{l}\rfloor\\ 0&1&0\\ 0&0&1 \end{bmatrix} \]

这道题唯一算得上是坑的应该是\(n,p\)的大小,当\(p/l==0\)直接矩阵加速到底即可,注意\(r\)不能超过\(n\)

code

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
#define mod 1000000007
struct Matrix {
	ll c[5][5];
	void init() {
		memset( c, 0, sizeof( c ) );
	}
	Matrix operator * ( const Matrix &a ) {
		Matrix ans;
		ans.init();
		for( int i = 1;i <= 3;i ++ )
			for( int j = 1;j <= 3;j ++ )
				for( int k = 1; k <= 3;k ++ )
					ans.c[i][j] = ( ans.c[i][j] + c[i][k] * a.c[k][j] ) % mod;
		return ans;
	}
}V;
ll T, A, B, C, D, P, n;
ll ans1, ans2;

Matrix qkpow( Matrix a, int b ) {
	Matrix ans;
	ans.init();
	for( int i = 1;i <= 3;i ++ ) ans.c[i][i] = 1;
	while( b ) {
		if( b & 1 ) ans = ans * a;
		a = a * a;
		b >>= 1;
	}
	return ans;
}

signed main() {
	scanf( "%lld", &T );
	while( T -- ) {
		scanf( "%lld %lld %lld %lld %lld %lld", &A, &B, &C, &D, &P, &n );
		if( n == 1 ) { printf( "%lld\n", A ); continue; }
		if( n == 2 ) { printf( "%lld\n", B ); continue; }
		ans1 = B, ans2 = A;
		for( int l = 3, r;l <= n;l = r + 1 ) {
			if( P / l == 0 ) {
				V.init();
				V.c[1][1] = D, V.c[1][2] = C;
				V.c[2][1] = V.c[3][3] = 1;
				V = qkpow( V, n - l + 1 );
				ans1 = ( V.c[1][1] * ans1 % mod + V.c[1][2] * ans2 % mod + V.c[1][3] ) % mod;
				ans2 = ( V.c[2][1] * ans1 % mod + V.c[2][2] * ans2 % mod + V.c[2][3] ) % mod;
				break;
			}
			r = min( n, P / ( P / l ) );
			V.init();
			V.c[1][1] = D, V.c[1][2] = C, V.c[1][3] = P / l;
			V.c[2][1] = V.c[3][3] = 1;
			V = qkpow( V, r - l + 1 );
			ll newans1 = ( V.c[1][1] * ans1 % mod + V.c[1][2] * ans2 % mod + V.c[1][3] ) % mod;
			ll newans2 = ( V.c[2][1] * ans1 % mod + V.c[2][2] * ans2 % mod + V.c[2][3] ) % mod;
			ans1 = newans1, ans2 = newans2;
		}
		printf( "%lld\n", ans1 );
	} 
	return 0;
}

T2:Bamboo Partition

title

传送门

solution

\[∑_{i=1}^nd−((a_i−1)\%d+1)≤k \]

扫描二维码关注公众号,回复: 11249440 查看本文章

\[=\sum_{i=1}^nd-\sum_{i=1}^n(a_i-1-\lfloor\frac{a_i-1}{d}\rfloor*d+1)\le k \]

\[=n*d-\sum_{i=1}^na_i+\sum_{i=1}^n\lfloor\frac{a_i-1}{d}\rfloor*d\le k \]

\[d(n+\sum_{i=1}^n\lfloor\frac{a_i-1}{d}\rfloor*d)\le k+\sum_{i=1}^na_i \]

\(\lfloor\frac{a_i-1}{d}\rfloor\)有根号的取值,我们直接分块即可

code

#include <cstdio>
#include <iostream>
using namespace std;
#define N 105
#define int long long
int n, k, Max, ans;
int a[N];

signed main() {
	scanf( "%lld %lld", &n, &k );
	for( int i = 1;i <= n;i ++ ) 
		scanf( "%lld", &a[i] ), k += a[i], Max = max( Max, a[i] - 1 );
	for( int l = 1, r, sum;l <= Max;l = r + 1 ) {
		r = Max, sum = 0;
		for( int i = 1;i <= n;i ++ )
			if( a[i] - 1 >= l ) {
				sum += ( a[i] - 1 ) / l;
				r = min( r, ( a[i] - 1 ) / ( ( a[i] - 1 ) / l ) );
			}
		if( l <= k / ( sum + n ) ) ans = max( ans, min( k / ( sum + n ), r ) );
	}
	if( Max < k / n ) ans = max( ans, k / n );
	printf( "%lld", ans );
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/mamamoo/p/12939806.html