【套题】qbxt国庆刷题班D1

Day1

事实上D1的题目还是比较简单的= =然而D1T2爆炸了就十分尴尬……错失一波键盘

看题

T1

传送门

Description

现在你手里有一个计算器,上面显示了一个数S,这个计算器十分的牛逼,他只有两个按钮,分别可以把屏幕上显示的数加上1或者减去1。并且,如果计算器屏幕上的数变成了负数,那么计算器就会损坏。现在你想要在K次操作之内吧屏幕上的数字变成T,而且不让计算器损坏,求一共有多少种方案。
两种方案不同当且仅当按钮被按下的序列不同

Input

一行三个整数S,T,K

Output

一行一个正整数,表示答案

Sample Input

0 1 3

Sample Output

3

Hint

For All:
0  S,T,K  100000
For 30 percents:
S,T,K  10
For 60 percents:
S,T,K  1000

Solution

前30分枚举加和减

60分做法:DP。

fi,j为,第i次操作将计算器变成j的方案数。转移显然,枚举第i次加一还是减一。

f_{i,j}=f_{i-1,j-1}+f_{i-1}{j+1}$$。当$j=0$时不能从$j-1$转移。答案显然就是$\sum_{i=0}^{k}~f_{k,T}$,边界为$f_{0,S}=1$满分做法:数学推导。由于$S$到$T$的方案数严格等价于$T$到$S$的方案数,故不妨设$S~\leq~T$考虑题目事实上等价于在一个平面直角坐标系中,有一个点$(S,0)$,求这个点到$(T,k)$的方案数。其中$0~\leq~k~\leq~K$每次移动只能从$(x,y)$移动到$(x+1,y+1)$或$(x-1)(y+1)$。其中不允许越过$x=0$这条线。考虑这么做的方案数,等价于将坐标轴旋转$45°$,以原先的$(S,0)$为原点,不允许越过$y=x+S$这条直线,到达$(T-S,k)$的方案数。先考虑不存在不许越过直线的限制,那么方案数即为$C_{T-S+k}^{k}$。考虑不合法的方案。发现将不合法的方案在直线下方的部分关于直线对称后与他关于直线的对称点到目标的方案一一对应。于是显然另一个方案数可以求出。做差即为答案。### Code~~我懒得写了所以就把std放上来了~~~~这std写的真丑~~```cpp#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;const int N = (int)2e5, mod = (int)1e9 + 7;typedef long long ll;int S, T, K;int fac[N + 10], ifac[N + 10];int pow(int x, int y) {    ll t = x, r = 1;    for ( ; y; y >>= 1, t = t * t % mod)        if (y & 1) r = r * t % mod;    return r;}void preprocessing() {    fac[0] = 1;    for (int i = 1; i <= N; ++i) fac[i] = (ll)fac[i - 1] * (ll)i % mod;    ifac[N] = pow(fac[N], mod - 2);    for (int i = N - 1; i >= 0; --i) ifac[i] = (ll)ifac[i + 1] * (ll)(i + 1) % mod;}int c(int n, int r) {    return (ll)fac[n] * (ll)ifac[r] % mod * (ll)ifac[n - r] % mod;}int main() {        preprocessing();    scanf("%d %d %d", &S, &T, &K);    if (S > T) swap(S, T);    int ans = 0;    for (int i = 0; i <= K; ++i) {        if ((i + T - S) & 1) continue;        int x = (i - T + S) >> 1, y = (i + T - S) >> 1;        if (x < 0) continue;        (ans += c(x + y, x)) %= mod;        if (x > S) (ans += (mod - c(x + y, x - S - 1))) %= mod;    }    printf("%d\n", ans);    return 0;} ```## T2[传送门](https://www.luogu.org/problemnew/show/T50010)### Description有一个工厂一共有$n$个排成一排的机器,其中第$i$台机器的效率是$e_i$。机器有开或关两种状态,显然当所有机器都开着时工作效率可以达到最大。但是由于工厂的供电系统出现了故障,不能够同时开启任意连续$k$台机器,否则工厂就会爆炸。求工厂在不发生爆炸的前提下能达到的最大效率### input 第一行两个整数$n$和$k$接下来$n$行,每行一个整数代表$e_i$### Output一行一个数代表答案### Sample Input ```5 212345```### Sample Output```12```### Hint$For~All:$$1~\leq~n,k~\leq~10^5~,~1~\leq~e_i~\leq~10^9$$For~30~percents:$$1~\leq~n~\leq~100$### SolutionDP。考虑设$f_i$为前$i$个的答案,其中一定不选第$i$个。显然可以通过枚举哪一个不选进行转移。$f_i=$$\max\{f_j+e_{j+1}+e_{j+2}+...+e_{i}\}$,其中满足$i-k~<~j~<~i$。$e_i$显然可以前缀和处理。另外发现因为$k$恒定,所以转移的左端点时单调不降的。于是可以单调队列把整个复杂度降低到$O(n)$。事实上使用线段树维护区间最大值也是可以的。## Code```cpp#include<cstdio>#define rg register#define ci const int#define cl const long long intnamespace IO {    char buf[110];}typedef long long int ll;template <typename T>inline void qr(T &x) {    char ch=getchar(),lst=' ';    while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();    while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();    if(lst == '-') x=-x;}template <typename T>inline void write(T x,const char aft,const bool pt) {    if(x < 0) {putchar('-');x=-x;}    rg int top=0;    do {        IO::buf[++top]=x%10+'0';x/=10;    } while(x);    while(top) putchar(IO::buf[top--]);    if(pt) putchar(aft);}template <typename T>inline T mmax(const T a,const T b) {return a > b ? a : b;}template <typename T>inline T mmin(const T a,const T b) {return a < b ? a : b;}template <typename T>inline T mabs(const T x) {return x < 0 ? -x : x;}template <typename T>inline void mswap(T &a,T &b) {    T temp=a;a=b;b=temp;}const int maxn = 100010;int n,k,front,end;ll frog[maxn],que[maxn],sum[maxn];int main() {    qr(n);qr(k);    for(rg int i=1;i<=n;++i) {qr(sum[i]);sum[i]+=sum[i-1];}    front=end=1;    for(rg int i=1;i<=n;++i) {        if(i-que[front] > k) ++front;        while((front <= end) && ((frog[que[end]]-sum[que[end]]) <= (frog[i]-sum[i]))) --end;        que[++end]=i;        frog[i+1]=frog[que[front]]-sum[que[front]]+sum[i];    }    write(frog[n+1],'\n',true);    return 0;}```## T3[传送门](https://www.luogu.org/problemnew/show/T50011)### Description![qwq](https://cdn.luogu.org/upload/pic/35123.png )### Input![qwq](https://cdn.luogu.org/upload/pic/35124.png)### Output对于每组询问输出一行代表答案### Sample Input```6M 1 6C 1M 2 4M 2 6C 3C 4```### Sample Output```102```### Solution这不是没穿衣服的带权并查集嘛### Code```cpp// i forgot to reset the seed of the rand// maybe i will get zero pts// upd: i ain't get WA for this task// i feel very happy#include<cstdio>#define rg register#define ci const int#define cl const long long intnamespace IO {    char buf[110];}template <typename T>inline void qr(T &x) {    char ch=getchar(),lst=' ';    while((ch > '9') || (ch < '0')) lst=ch,ch=getchar();    while((ch >= '0') && (ch <= '9')) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();    if(lst == '-') x=-x;}template <typename T>inline void write(T x,const char aft,const bool pt) {    if(x < 0) {putchar('-');x=-x;}    rg int top=0;    do {        IO::buf[++top]=x%10+'0';x/=10;    } while(x);    while(top) putchar(IO::buf[top--]);    if(pt) putchar(aft);}template <typename T>inline T mmax(const T a,const T b) {return a > b ? a : b;}template <typename T>inline T mmin(const T a,const T b) {return a < b ? a : b;}template <typename T>inline T mabs(const T x) {return x < 0 ? -x : x;}template <typename T>inline void mswap(T &a,T &b) {    T temp=a;a=b;b=temp;}const int maxn = 30010;int up[maxn],down[maxn],dist[maxn];int findup(ci);int finddown(ci);int main() {    freopen("cubes.in","r",stdin);    freopen("cubes.out","w",stdout);    rg int m=0;qr(m);    for(rg int i=1;i<=maxn;++i) up[i]=i,down[i]=i,dist[i]=0;    rg int a,b;rg char ch;    while(m--) {        ch=getchar();        while((ch != 'M') && (ch != 'C')) ch=getchar();        if(ch == 'M') {            a=b=0;qr(a);qr(b);            a=finddown(a);b=findup(b);            down[a]=b;up[b]=a;dist[a]=1;        }        else {            a=0;qr(a);            finddown(a);            write(dist[a],'\n',true);        }    }    return 0;}int findup(ci x) { return up[x] != x ? up[x]=findup(up[x]) : x; }int finddown(ci x) {    if(down[x] == x) return x;    int tk=finddown(down[x]);    dist[x]+=dist[down[x]];    return down[x]=tk;}```## Summary这套题大概是6天里面最简单的一套了……起码有260保底……然而竟然挂在了最拿手的DP上……在写DP的时候发现有一部分转移无法优化时,可以考虑这一块转移是否是必须的,如果不是,可以直接删除该转移一定记得srand!

posted @   一扶苏一  阅读(219)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示