AtCoder Beginner Contest 251 Solution更好的阅读体验戳此进入题面链接题面 Luogu 链接老样子abc太水了就跳了[ABC251D] At Most 3 (Contestant ver.)题面SolutionCode[ABC251E] Takahashi and Animals题面SolutionCode[ABC251F] Two Spanning Trees题面SolutionCodeG 是计算几何,暂时跳了,以后有机会再回来做[ABC251Ex] Fill Triangle题面SolutionCodeUPD
给你整数
显然按照十进制拆分成三组即可,即
xxxxxxxxxx47123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int > 23inline T read(void);24
25int main(){26 printf("297\n");27 for(int i = 1; i <= 99; ++i)printf("%d %d %d ", i, i * 100, i * 10000);28 printf("\n");29 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);30 return 0;31}32
33template < typename T >34inline T read(void){35 T ret(0);36 int flag(1);37 char c = getchar();38 while(c != '-' && !isdigit(c))c = getchar();39 if(c == '-')flag = -1, c = getchar();40 while(isdigit(c)){41 ret *= 10;42 ret += int(c - '0');43 c = getchar();44 }45 ret *= flag;46 return ret;47}有
输出喂食所有动物需要的最小花费。
DP 显然,令
xxxxxxxxxx63123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int >23inline T read(void);24
25int N;26int a[310000];27ll dp[310000][2];28
29int main(){30 N = read();31 for(int i = 1; i <= N; ++i)a[i] = read();32 memset(dp, 0x3f, sizeof dp);33 dp[1][1] = a[1];34 for(int i = 2; i <= N; ++i)35 dp[i][0] = dp[i - 1][1],36 dp[i][1] = min(dp[i - 1][1], dp[i - 1][0]) + a[i];37 // for(int i = 1; i <= N; ++i)printf("%d: 0 = %lld, 1 = %lld\n", i, dp[i][0], dp[i][1]);38 ll ans = min(dp[N][1], dp[N][0]);39 dp[1][0] = 0;40 for(int i = 2; i <= N; ++i)41 dp[i][0] = dp[i - 1][1],42 dp[i][1] = min(dp[i - 1][1], dp[i - 1][0]) + a[i];43 ans = min(ans, dp[N][1]);44 printf("%lld\n", ans);45 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);46 return 0;47}48
49template < typename T >50inline T read(void){51 T ret(0);52 int flag(1);53 char c = getchar();54 while(c != '-' && !isdigit(c))c = getchar();55 if(c == '-')flag = -1, c = getchar();56 while(isdigit(c)){57 ret *= 10;58 ret += int(c - '0');59 c = getchar();60 }61 ret *= flag;62 return ret;63}给定无向连通简单图,求其两个以
前者对图 DFS,后者对图 BFS,证明显然。
xxxxxxxxxx83123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
22template < typename T = int >23inline T read(void);24
25struct Edge{26 Edge* nxt;27 int to;28 OPNEW;29}ed[410000];30ROPNEW(ed);31Edge* head[410000];32
33int N, M;34bool vis[210000];35
36void dfs(int p = 1){37 vis[p] = true;38 for(auto i = head[p]; i; i = i->nxt){39 if(vis[SON])continue;40 printf("%d %d\n", p, SON);41 dfs(SON);42 }43}44void bfs(void){45 memset(vis, false, sizeof vis);46 queue < int > cur;47 cur.push(1), vis[1] = true;48 while(!cur.empty()){49 int tp = cur.front(); cur.pop();50 for(auto i = head[tp]; i; i = i->nxt){51 if(vis[SON])continue;52 printf("%d %d\n", tp, SON);53 vis[SON] = true, cur.push(SON);54 }55 }56}57
58int main(){59 N = read(), M = read();60 for(int i = 1; i <= M; ++i){61 int s = read(), t = read();62 head[s] = new Edge{head[s], t};63 head[t] = new Edge{head[t], s};64 }dfs(), bfs();65 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);66 return 0;67}68
69template < typename T >70inline T read(void){71 T ret(0);72 int flag(1);73 char c = getchar();74 while(c != '-' && !isdigit(c))c = getchar();75 if(c == '-')flag = -1, c = getchar();76 while(isdigit(c)){77 ret *= 10;78 ret += int(c - '0');79 c = getchar();80 }81 ret *= flag;82 return ret;83}存在序列
首先可以尝试随意给定一个序列
不难发现这玩意每一项实际上就是二项式系数,或者说杨辉三角。并且还能发现,对于每一行的元素,它们的系数均相同,不同的只是将下标整体向右平移了一位。
此时我们便可以根据这个性质,求出对于第
显然我们想要算出
显然序列

观察发现,这个东西平移之后,对于大多数的
具体地当我们移动询问区间的时候,遍历所有段,如果某一段的右端点在当前区间内,那么显然指向这一段的组合数会移动到下一段中,所以需要减掉前面的加上现在的。注意移动这步实际上是
于是现在的问题就仅剩如何求
首先还是考虑之前的思路,一定会有很多段的相同的
所以这个东西显然需要快速处理一段组合数,可以考虑做一个组合数的前缀和,这样即可
于是现在问题再次转化为如何快速求这种形式的组合数前缀和,可以参考该题:LG-P4345 [SHOI2015]超能粒子炮·改。
具体地,对于求
然后发现对于前面的
然后继续转化:
此时对比我们之前设的
然后我们只要随便与处理一下
考虑这个东西的复杂度,用主定理推导一下即可:
至此我们就终于完成了这道题。
xxxxxxxxxx115123
45678910
11using namespace std;12
13mt19937 rnd(random_device{}());14int rndd(int l, int r){return rnd() % (r - l + 1) + l;}15bool rnddd(int x){return rndd(1, 100) <= x;}16
17typedef unsigned int uint;18typedef unsigned long long unll;19typedef long long ll;20typedef long double ld;21
2223//7^624
25template < typename T = int >26inline T read(void);27
28int f[10][10];29int N, M, K;30int origin(0);31int sumf[210];32int lucas_div[SPL + 10], lucas_mod[SPL + 10];33struct Blk{int l, r; int val;} blk[210];34
35int qpow(int a, int b){36 int ret(1), mul(a);37 while(b){38 if(b & 1)ret = ret * mul % MOD;39 b >>= 1;40 mul = mul * mul % MOD;41 }return ret;42}43int fact[10], inv[10];44void Init(void){45 fact[0] = 1;46 for(int i = 1; i < MOD; ++i)fact[i] = fact[i - 1] * i % MOD;47 inv[MOD - 1] = qpow(fact[MOD - 1], MOD - 2);48 for(int i = MOD - 2; i >= 0; --i)inv[i] = inv[i + 1] * (i + 1) % MOD;49}50int GetC(int n, int m){51 if(n < m)return 0;52 return fact[n] * inv[m] % MOD * inv[n - m] % MOD;53}54int Lucas(ll n, ll m){55 if(n < MOD && m < MOD)return GetC(n, m);56 return Lucas(n / MOD, m / MOD) * GetC(n % MOD, m % MOD) % MOD;57}58int O1Lucas(ll m){59 return (lucas_div[m / SPL] * lucas_mod[m % SPL]) % MOD;60}61void InitF(void){62 for(int i = 0; i <= MOD - 1; ++i)f[i][0] = f[0][i] = 1;63 for(int i = 1; i <= MOD - 1; ++i)64 for(int j = 1; j <= MOD - 1; ++j)65 f[i][j] = (f[i][j - 1] + Lucas(i, j)) % MOD;66}67int F(ll n, ll k){68 if(n < 0 || k < 0)return 0;69 if(n < MOD && k < MOD)return f[n][k];70 return (f[n % MOD][MOD - 1] * F(n / MOD, k / MOD - 1) % MOD + Lucas(n / MOD, k / MOD) * f[n % MOD][k % MOD] % MOD) % MOD;71}72
73int main(){74 Init(), InitF();75 N = read(), M = read(), K = read();76 for(int i = 0; i <= SPL; ++i)lucas_div[i] = Lucas((N - K) / SPL, i), lucas_mod[i] = Lucas((N - K) % SPL, i);77 int curl(1);78 for(int i = 1; i <= M; ++i)blk[i].val = read(), blk[i].l = curl, blk[i - 1].r = blk[i].l - 1, curl += read();79 blk[M].r = N; int lim = N - K + 1;80 for(int i = 1; i <= M; ++i)81 sumf[i] = (F(N - K, blk[i].r - 1) - F(N - K, blk[i].l - 2) + MOD) % MOD;82 for(int i = 1; i <= M; ++i){83 int l = blk[i].l, r = blk[i].r;84 if(l > lim)break;85 if(r <= lim)(origin += sumf[i] * blk[i].val % MOD) %= MOD;86 else (origin += (F(N - K, lim - 1) - F(N - K, l - 2) + MOD) % MOD * blk[i].val % MOD) %= MOD;87 }printf("%d ", origin);88 int cl = 1, cr = lim;89 for(int i = 2; i <= K; ++i){90 for(int m = 1; m <= M; ++m){91 int r = blk[m].r;92 if(cl <= r && r <= cr)93 origin = (origin - O1Lucas(r - cl) * blk[m].val % MOD + O1Lucas(r - cl) * blk[m + 1].val % MOD + MOD) % MOD;94 }++cl, ++cr;95 printf("%d ", origin);96 }printf("\n");97 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);98 return 0;99}100
101template < typename T >102inline T read(void){103 T ret(0);104 int flag(1);105 char c = getchar();106 while(c != '-' && !isdigit(c))c = getchar();107 if(c == '-')flag = -1, c = getchar();108 while(isdigit(c)){109 ret *= 10;110 ret += int(c - '0');111 c = getchar();112 }113 ret *= flag;114 return ret;115}update-2022_12_02 初稿