0 碎碎念
实数二分,永远的调不出来(。◕∀◕。)
但是这算法还挺有意思的,故写到博客
Continue reading “WQS 二分入门 – Codeforces 739E”「Jump up HIGH!!」
即 Codeforces Round #695 (Div. 2)
许久不打变得更菜了…
给定 $n$ 个板子,每个板子上有一个相同的数字 $x ( 0 \leq x \leq 9 )$
随机选择一个数字 $y(1 \leq y \leq n)$,令板子 $i$ 上的数字变成 $ x + |y – i| \pmod 10$
显然,输出 $98\{987654321\}$ 的前 $n$ 位即可
#include <cstdio>
int main() {
int T;
scanf( "%d", &T );
while( T -- ) {
int n;
scanf( "%d", &n );
if( n == 1 )
printf( "9" );
else {
printf( "98" );
int cur = 9;
for( int i = 3; i <= n; i ++ ) {
printf( "%d", cur );
cur ++;
if( cur >= 10 )
cur = 0;
}
}
printf( "\n" );
}
}
Continue reading “Codeforces Round 1467 题目大意 & 解题报告” 给你两个正多边形,一个 $n$ 条边 $A$ ,一个 $m$ 条边 $B$
问 $B$ 有没有可能被 $A$ 包含且所有顶点都与 $A$ 的某一个节点重合
有输出 YES
,否则输出 NO
判 $n \bmod m = 0$ 就可以了
#include <cstdio>
int T;
int n, m;
int main() {
scanf( "%d", &T );
while( T -- ) {
scanf( "%d%d", &n, &m );
printf( "%s\n", ( n % m == 0 )? "YES": "NO" );
}
}
给你一个长度为 $n$ 的序列 $a$, 你可以将 $a$ 重新排序,使其满足 $j – a_j \neq i – a_i$
输出任何一个即可
保证有解
$n \leq 100$
$$
\begin{aligned}
j – a_j & \neq i – a_i \\
j – i & \neq a_j – a_i
\end{aligned}
$$
直接从大到小输出
// Woshiluo Luo<[email protected]>
// 2020/03/09 22:40:32
#include <cstdio>
#include <cstring>
#include <algorithm>
template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }
const int N = 110;
int T;
int n;
int a[N];
int main() {
scanf( "%d", &T );
while( T -- ) {
scanf( "%d", &n );
for( int i = 1; i <= n; i ++ ) {
scanf( "%d", &a[i] );
}
std::sort( a + 1, a + n + 1 );
for( int i = n; i >= 1; i -- ) {
printf( "%d ", a[i] );
}
printf( "\n" );
}
}
给你两个长度为 $n$ 的数列 $a,v$
其中 $a$ 通过输入提供,$v$ 初始所有值为 $0$
接下来,对于第 $i$ 次操作(从 $0$ 计数),你可以
问你是否通过多次操作后,使 $v$ 变成 $a$
能输出 YES
,否则输出 NO
首先对于每个数字 $a$, 考虑其是否可以变成多个 $k^i$ 的和(不能有重复的 $i$)
能的话算出来,看看有没有和之前重复的,有就不可能
不能的话直接没有可能
// Woshiluo Luo<[email protected]>
// 2020/03/09 22:58:45
#include <cstdio>
#include <cstring>
#include <algorithm>
template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }
const int N = 110;
int T;
int n;
long long k;
bool vis[N];
long long a[N];
inline void wrong() {
printf( "NO\n" );
}
inline void right() {
printf( "YES\n" );
}
void calc() {
for( int i = 1; i <= n; i ++ ) {
if( a[i] == 0 ) {
continue;
}
long long cur = a[i];
int cnt = 1;
while( cur ) {
int tmp = cur % k;
if( tmp > 1 ) {
wrong();
return ;
}
if( tmp == 1 ) {
if( vis[cnt] == false )
vis[cnt] = true;
else {
wrong();
return ;
}
}
cur /= k;
cnt ++;
}
}
right();
}
int main() {
scanf( "%d", &T );
while( T -- ) {
memset( vis, 0, sizeof(vis) );
scanf( "%d%lld", &n, &k );
for( int i = 1; i <= n; i ++ ) {
scanf( "%lld", &a[i] );
}
calc();
}
}
你需要寻找这样的数列个数
个数对 $998244353$ 取模后输出
$2 \leq n \leq m \leq 2 \times 10^5$
式子题,看 Code 去
// Woshiluo Luo<[email protected]>
// 2020/03/09 23:21:18
#include <cstdio>
#include <cstring>
#include <algorithm>
template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }
const int N = 2e5 + 1e4;
const int mod = 998244353;
inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline void add_eq( int &a, int b ) { a = ( a + b ) % mod; }
inline void mul_eq( int &a, int b ) { a = ( 1LL * a * b ) % mod; }
int ksm( int a, int p ) {
int res = 1;
while(p) {
if( p & 1 )
res = mul( res, a );
a = mul( a, a );
p >>= 1;
}
return res;
}
inline int get_inv( int a ) { return ksm( a, mod - 2 ); }
int n, m, sum, ans;
int fact[N], inv[N];
void init() {
fact[1] = 1;
for( int i = 2; i <= m; i ++ ) {
fact[i] = mul( fact[ i - 1 ], i );
}
inv[m] = get_inv( fact[m] );
for( int i = m - 1; i >= 1; i -- ) {
inv[i] = mul( inv[ i + 1 ], i + 1 );
}
inv[0] = 1;
fact[0] = 1;
}
// Get C^a_b
inline int C( int a, int b ) {
if( a <= 0 )
return 1;
if( b <= 0 )
return 1;
return mul( mul( fact[b], inv[ b - a ] ), inv[a] );
}
int main() {
#ifdef woshiluo
freopen( "d.in", "r", stdin );
freopen( "d.out", "w", stdout );
#endif
scanf( "%d%d", &n, &m );
init();
for( int i = n - 1; i <= m; i ++ ) {
add_eq( sum, mul( C( n - 3, i - 2 ), mul( m - i + 1, n - 2 ) ) );
}
for( int i = 2; i < n; i ++ ) {
add_eq( ans, mul( sum, C( i - 2, n - 3 ) ) );
}
printf( "%d\n", ans );
}
这好像是个原题
给你一个长度为 $n$ 的数列 $a$
如果 $a_i = a_{i + 1}$, 那么这两个数可以合并成 $a_i + 1$
问最小数列长度
$1 \leq a_i \leq 1000, 1 \leq n \leq 500$
区间 dp
设 $f_{i,j}$ 为 $i$ 到 $j$ 最小长度
$merged_{i,j}$ 为 $i$ 到 $j$ 合并出来的数字
然后就是标准板子了
// Woshiluo Luo<[email protected]>
// 2020/03/10 15:50:48
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 510;
template<class T>
T Min( T _a, T _b ) { return _a < _b? _a: _b; }
template<class T>
T Max( T _a, T _b ) { return _a > _b? _a: _b; }
template<class T>
T chk_Min( T &_a, T _b ) { return _a = (_a < _b? _a: _b); }
template<class T>
T chk_Max( T &_a, T _b ) { return _a = (_a > _b? _a: _b); }
int n;
int a[N];
int f[N][N], merged[N][N];
int main() {
#ifdef woshiluo
freopen( "e.in", "r", stdin );
freopen( "e.out", "w", stdout );
#endif
scanf( "%d", &n );
for( int i = 1; i <= n; i ++ ) {
scanf( "%d", &a[i] );
f[i][i] = 1;
merged[i][i] = a[i];
}
for( int len = 2; len <= n; len ++ ) {
for( int left = 1, rig = len; rig <= n; left ++, rig ++ ) {
f[left][rig] = rig - left + 1;
for( int mid = left; mid < rig; mid ++ ) {
int &f_left = f[left][mid], &f_rig = f[ mid + 1 ][rig],
&merge_left = merged[left][mid], &merge_rig = merged[ mid + 1 ][rig];
chk_Min( f[left][rig], f_left + f_rig );
if( f_left == 1 && f_rig == 1 && merge_left == merge_rig ) {
f[left][rig] = 1;
merged[left][rig] = merge_left + 1;
}
}
}
}
printf( "%d\n", f[1][n] );
}
裸的要死的数位 DP 题目
一眼看过去,平方和,有点懵
但是维护平方和也是老套路了
维护 $sum$, $cnt$, $pow_sum$ 就可以了
代码写的着急,会有一些不太好看
#include <cstdio>
const int mod = 1e9 + 7;
inline int add( int a, int b ) { return ( a + b ) % mod; }
inline int mul( int a, int b ) { return ( 1LL * a * b ) % mod; }
inline int power( int a ) { return mul( a, a ); }
int T, max_len;
long long left, rig;
int _count[110][2][10][10][10], _sum[110][2][10][10][10], _pow[110][2][10][10][10];
int max_count[110][2][10][10][10], max_sum[110][2][10][10][10], max_pow[110][2][10][10][10];
bool _vis[110][2][10][10][10];
int a[110];
inline int length( int cur, int len ) {
int res = cur;
while( len > 0 ) {
res = mul( 10, res );
len --;
}
return res;
}
struct node {
int len, cur, seven, rem, base_rem;
bool max;
int& count() {
if( max )
return max_count[len][seven][rem][cur][base_rem];
return _count[len][seven][rem][cur][base_rem];
}
int& sum() {
if( max )
return max_sum[len][seven][rem][cur][base_rem];
return _sum[len][seven][rem][cur][base_rem];
}
int& pow() {
if( max )
return max_pow[len][seven][rem][cur][base_rem];
return _pow[len][seven][rem][cur][base_rem];
}
bool& vis() {
return _vis[len][seven][rem][cur][base_rem];
}
void print() {
// printf( "%d %d %d %d %d %d\n", len, cur, seven, rem, base_rem, max );
// printf( "%d %d %d\n", count(), sum(), pow() );
}
};
int dfs( node cur ) {
if( ( ! cur.max ) && cur.vis() )
return cur.pow();
if( cur.len == 0 ) {
if( cur.seven || cur.rem == 0 || cur.base_rem == 0 ) {
cur.count() = cur.sum() = cur.pow() = 0;
return cur.pow();
}
cur.count() = 1; cur.sum() = cur.cur; cur.pow() = power( cur.cur );
return cur.pow();
}
int &cur_count = cur.count();
int &cur_sum = cur.sum();
int &cur_pow = cur.pow();
if( cur.max )
cur_count = cur_sum = cur_pow = 0;
for( int i = 0; i <= ( cur.max? a[cur.len]: 9 ); i ++ ) {
node nxt = cur;
nxt.len -= 1; nxt.seven = ( cur.seven || ( i == 7 ) ); nxt.cur = i; nxt.max = ( cur.max && i == a[cur.len] );
nxt.rem = ( cur.rem * 10 + i ) % 7; nxt.base_rem = ( cur.base_rem + i ) % 7;
dfs( nxt );
cur_count = add( cur_count, nxt.count() );
cur_sum = add( cur_sum, add( mul( length( cur.cur, cur.len ), nxt.count() ), nxt.sum() ) );
cur_pow = add( cur_pow, add( nxt.pow(), add( mul( nxt.count(), power( length( cur.cur, cur.len ) ) ),
mul( mul( 2, length( cur.cur, cur.len ) ), nxt.sum() ) ) ) );
}
if( cur.max == false )
cur.vis() = true;
cur.print();
return cur_pow;
}
int sum( long long _a ) {
if( _a == 0 )
return 0;
if( _a < 0 )
return 0;
max_len = 0;
while( _a ) {
a[ ++ max_len ] = _a % 10;
_a /= 10;
}
// printf( "ans: %d\n", dfs( (node){ max_len, 0, 0, 0, 0, true } ) );
return dfs( (node){ max_len, 0, 0, 0, 0, true } );
}
int main() {
#ifdef woshiluo
freopen( "hdu.4507.in", "r", stdin );
freopen( "hdu.4507.out", "w", stdout );
#endif
scanf( "%d", &T );
while( T -- ) {
scanf( "%lld%lld", &left, &rig );
if( left == 0 )
printf( "%d\n", ( sum(rig) + mod ) % mod );
else
printf( "%d\n", ( add( sum(rig), - sum( left - 1 ) ) + mod ) % mod );
}
}
树形 DP 要么模板题,要么神仙题
这个题就属于不太正常的
$f_{i,j}$
其中 $i$ 代表当前节点
$j$ 代表子树中选择 $j$ 个黑点,所能对答案产生的贡献
有了这个思路,后面的东西就是标准的树上背包了
#include <cstdio>
#include <cstring>
inline int Min(int a, int b) { return a < b? a : b; }
inline long long Max(long long a, long long b) { return a > b? a : b; }
const int N = 2100;
int n, m;
int size[N];
// Edge Start
struct edge {
int to, val, next;
} e[N << 1];
int ehead[N], ecnt;
inline void add_edge(int now, int to, int val) {
ecnt ++;
e[ecnt].to = to;
e[ecnt].val = val;
e[ecnt].next = ehead[now];
ehead[now] = ecnt;
}
// Edge End
// DP Start
long long f[N][N];
void dp(int now, int la) {
size[now] = 1;
f[now][0] = f[now][1] = 0;
for(int i = ehead[now]; i; i = e[i].next) {
if( e[i].to == la )
continue;
dp(e[i].to, now);
size[now] += size[ e[i].to ];
for(int j = Min(size[now], m); j >= 0; j--) {
for(int k = 0; k <= Min(size[ e[i].to ], j); k++) {
if( f[now][ j - k ] == -1 )
continue;
long long val = 1LL * ( 1LL * k * ( m - k ) + 1LL * ( size[ e[i].to ] - k ) * ( n - m - size[ e[i].to ] + k ) ) * e[i].val;
f[now][j] = Max( f[now][j], f[now][j - k] + f[ e[i].to ][k] + val);
}
}
}
}
// DP End
int main() {
#ifdef woshiluo
freopen("luogu.3177.in", "r", stdin);
freopen("luogu.3177.out", "w", stdout);
#endif
scanf("%d%d", &n, &m);
for(int i = 1, u, v, w; i < n; i++) {
scanf("%d%d%d", &u, &v, &w);
add_edge(u, v, w);
add_edge(v, u, w);
}
memset(f, -1, sizeof(f));
dp(1, 0);
printf("%lld", f[1][m]);
fclose(stdin);
fclose(stdout);
}
考场上疯狂肝这道题目,结果少个特判
很明显,$n$ 只有三种情况
所以直接暴力即可
所以这是一道毒瘤模拟题目
Continue reading “中山纪念中学 Day 21 2019.08.21 解题报告 & 题解”真就数学题目呗
考场企图推正解,结果最后只推出了 60 分的,哭了
正解参见 欧几里得算法的应用.pdf
这是真的类欧几里得算法
Continue reading “中山纪念中学 Day 10 2019.08.10 解题报告 & 题解”考场上的时候总觉得题目非常的奇妙
因为一直循环下去不就完了吗?
直到后来我的同桌给我指点,原来把 DP 式子当方程解可以了
还是太菜啊
Continue reading “中山纪念中学 Day 4 2019.08.04 解题报告 & 题解”