QBXT考前刷题九套整理集合(留坑,望一天能整理完啊)
Round1:P146 出题人:ZHX
T1
Description
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没什么关系。小葱同学
最近醉心于动态规划的研究,他苦学百年,已经牢牢掌握了最长上升子序列的知识。小葱对于这
种单调不减的序列非常着迷,于是他灵机一动,挥笔写下了一个数𝑥,现在小葱同学希望找到一个
最大的小于等于𝑥的数,使得这个数的各个数位是单调不减的,求这个数。
Input
一行一个数x
Output
一行一个数代表答案
题解:对于一个数若在某一位违反了单调不下降的性质即num[i-1]>num[i],显然要调整这两位的数字
因为要找到一个最大的小于等于x的数,所以显然要将num[i-1]减小1,num[i]及以后的数均改为9,
注意特判x=0,注意输出时特判前导0。
考场得分:90’ 错因:没有特判x=0。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define maxn 100010 using namespace std; char s[maxn]; int num[maxn]; int pre[maxn]; int main() { freopen("increase.in","r",stdin); freopen("increase.out","w",stdout); scanf("%s",s+1); int len=strlen(s+1); if(len==1&&s[1]=='0') { puts("0\n"); return 0; } for(register int i=1;i<=len;++i) num[i]=s[i]-'0'; pre[1]=1; for(register int i=2;i<=len;++i) { if(num[i]==num[i-1]) pre[i]=pre[i-1]; else pre[i]=i; } bool flag=false; for(register int i=2;i<=len;++i) { if(num[i]<num[i-1]) { int tmp=pre[i-1]; --num[tmp]; for(register int j=1;j<=tmp;++j) { if((!flag)&&(num[j]==0)) continue; else printf("%d",num[j]),flag=true; } for(register int j=tmp+1;j<=len;++j) printf("9"); return 0; } if(i==len) { for(register int i=1;i<=len;++i) printf("%d",num[i]); } } return 0; }
T2
Description
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没什么关系。小葱同学自幼学习乘法
和加法,并且小葱同学意识到,正是因为有了加法和乘法,才能够计算1 + 1 = 2和1 × 1 = 1这种高深的问题。
现在小葱给你𝑁个数𝑎1, 𝑎2, ⋯ , 𝑎𝑁,求下列式子的值:
题解:归并排序+前缀和维护+快速乘
通过式子会发现满足相乘的ai和aj均为逆序对,然后通过找规律发现这两个逆序对在所有子串中出现的次数为
i*(n-j+1),通过归并排序找出逆序对,此时左区间的剩余所有数均与右集合待入辅助数组的数产生逆序对,此时
怎么办呢?循环??不太行,所以维护一下(ai*i)的前缀和即可,最后因为ai<=1e12直接乘会爆longlong,所以
要用快速乘。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<cmath> #define maxn 40010 using namespace std; const long long mod=1e12+7; long long n; struct nn { long long data; long long a; int pos; }; nn num[maxn],f[maxn]; long long ans; long long sum[maxn]; typedef long long ll; inline ll mult_mod(ll a, ll b, ll m) { ll res = 0; while(b){ if(b&1) res = (res+a)%m; a = (a+a)%m; b >>= 1; } return res; } inline void merge_sort(int l,int r) { if(l==r) return; int mid=(l+r)>>1; merge_sort(l,mid); merge_sort(mid+1,r); int p1=l,p2=mid+1; for(register int i=l;i<=r;++i) { if(p1<=mid&&p2<=r) { if(num[p1].data<=num[p2].data) { f[i].data=num[p1].data; f[i].pos=num[p1].pos; f[i].a=num[p1].a; ++p1; } else { long long tmp1=(sum[mid]-sum[p1-1])%mod; long long tmp2=(num[p2].data*(n-num[p2].pos+1))%mod; ans=(ans+mult_mod(tmp1,tmp2,mod))%mod; f[i].data=num[p2].data; f[i].pos=num[p2].pos; f[i].a=num[p2].a; ++p2; } } else if(p1<=mid) { f[i].data=num[p1].data; f[i].pos=num[p1].pos; f[i].a=num[p1].a; ++p1; } else if(p2<=r) f[i].data=num[p2].data,f[i].pos=num[p2].pos,f[i].a=num[p2].a,++p2; } for(register int i=l;i<=r;++i) { num[i].data=f[i].data; num[i].pos=f[i].pos; num[i].a=f[i].a; sum[i]=sum[i-1]+num[i].a; } return; } int main() { freopen("multiplication.in","r",stdin); freopen("multiplication.out","w",stdout); scanf("%lld",&n); for(register int i=1;i<=n;++i) { scanf("%lld",&num[i].data); num[i].pos=i; num[i].a=num[i].pos*num[i].data; sum[i]=sum[i-1]+num[i].a; } merge_sort(1,n); printf("%lld",ans%mod); return 0; }
T3
Description
小葱同学现在抵挡咕星人的进攻。咕星人的进攻非常猛烈,以至于小葱同学不得不进行防守。为了更好地防守咕星人的
进攻,小葱同学制作了𝑁面盾牌,其中第𝑖面盾牌的形状是左下角在(𝑎𝑖, 𝑏𝑖)右上角在(𝑐𝑖, 𝑑𝑖)的矩形。现在小葱将这𝑁面
盾牌组合在了一起,并且只有当这𝑁面盾牌组成了一个漂亮的矩形时,小葱才能够抵挡咕星人的进攻。一个漂亮的矩形指
的是盾牌不遗漏的覆盖了这个矩形内的每一个位置,并且每一个位置最多只被一个盾牌所覆盖(边界相交不算覆盖多次)。
现在给定你这𝑁面盾牌,你需要帮助小葱同学判断这𝑁面盾牌是否组成了一个漂亮的矩形。
题解:对于70分的做法,因为|x-y|<=200,所以可以染色。
对于100分的做法,咕咕咕。
Round2 出题人:CZH
Round3 出题人:DZY
Round4 出题人:ZHX
round5 出题人:LJH
T1:
Description
小 h 有重度拖延症。
小 h 在学校有各式各样的课程,比如数学分析,高等代数等等。每门课有都有若干项作
业,每项作业都有一个必须完成时间,在这个时间之前必须完成。
小 h 不喜欢一天之中做多个作业,也不希望一天中什么作业也不做,所以小 h 每天会
完成一项作业。
同时,小 h 也不喜欢两个作业的必须完成时间在同一天,所以,他对这些作业的必须完
成时间做了一次重排,保证了每项作业的必须完成时间互不相同。
现在小 h 有 n 项作业,第 i 项作业的必须完成时间为 i。小 h 认为,一项作业在其必须
完成时间前后两天之内完成是合理的。(也就是说,若一项作业的必须完成时间为 t,那么这
项作业在 t-2, t-1, t, t+1, t+2 天完成都是符合小 h 要求的)。当然了,小 h 只能在第 1 天到
第 n 天完成这些作业。也就是第 1 项作业只能在第 1,第 2 或者第 3 天完成。
小 h 一下想出了好多种安排的方法,使得小 h 能够完美地完成各项作业。但是小 h 不
知道到底有多少种安排的方法。你能帮帮他吗?
题解:推出递推式+矩阵乘法加速
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> using namespace std; long long g[10][10]; long long ans[10][10]; long long dx[10][10]; const int p=1e9+7; long long f[10]; long long res[10]; inline void ans_cf(int n) { for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) dx[i][j]=ans[i][j],ans[i][j]=0; for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) for(register int k=1;k<=n;k++) ans[i][j]=(ans[i][j]+(g[i][k]*dx[k][j])%p)%p; return; } inline void x_cf(int n) { for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) dx[i][j]=g[i][j],g[i][j]=0; for(register int i=1;i<=n;i++) for(register int j=1;j<=n;j++) for(register int k=1;k<=n;k++) g[i][j]=(g[i][j]+(dx[i][k]*dx[k][j])%p)%p; } inline void fast_pow(long long n,long long w) { while(w) { if(w%2==1) ans_cf(n); w/=2; x_cf(n); } } int main() { freopen("delay.in","r",stdin); freopen("delay.out","w",stdout); long long n,k; scanf("%lld",&n); g[1][1]=1; g[1][2]=1; g[1][3]=1; g[1][4]=1; g[1][5]=2; g[1][6]=2; g[2][1]=1; g[2][2]=0; g[2][3]=0; g[2][4]=0; g[2][5]=0; g[2][6]=0; g[3][1]=0; g[3][2]=1; g[3][3]=0; g[3][4]=0; g[3][5]=0; g[3][6]=0; g[4][1]=0; g[4][2]=0; g[4][3]=1; g[4][4]=0; g[4][5]=0; g[4][6]=0; g[5][1]=0; g[5][2]=1; g[5][3]=0; g[5][4]=0; g[5][5]=1; g[5][6]=0; g[6][1]=0; g[6][2]=0; g[6][3]=0; g[6][4]=0; g[6][5]=0; g[6][6]=1; for(register int i=1;i<=6;++i) for(register int j=1;j<=6;++j) ans[i][j]=g[i][j]; f[1]=1; f[2]=2; f[3]=6; f[4]=14; f[5]=31; f[6]=73; if(n<=6) { printf("%lld\n",f[n]); return 0; } f[1]=14; f[2]=6; f[3]=2; f[4]=1; f[5]=3; f[6]=1; fast_pow(6,n-5); for(register int i=1;i<=6;++i) res[1]=(res[1]+f[i]*ans[1][i])%p; printf("%lld\n",res[1]%p); return 0; }
T2
Description
小 h 准备规划一次旅行。
小 h 所处的国家是 C 国,他很喜欢旅行。最近他发现寒假将至,听说 J 国的风光很
好,便开始规划去 J 国旅行。J 国有 n 个城市,小 h 将这 n 个城市编号为 1--n。这个国
家,有些城市之间会有单向的公路相连,有些则不会。小 h 喜欢开车,因此,他希望他这
趟旅行是一个自驾游,自己开车游历国家。这个国家有 m 条公路,公路有长有短,汽车每
走一个单位的路程,就会花费一个单位的能源。小 h 并不富有,所以他规划中这次是一次
穷游,也就是花费尽可能少。而这趟自驾游中花费最多的就是汽车能源的费用了,所以他
希望花在补充能源上的费用尽可能少。
小 h 还是一个挑剔的人,他并不觉得每个城市他都值得去规划一趟旅行。他有 k 个心
目中值得旅行的城市,并且计划这趟自驾游是由一个值得旅行的城市去到另外一个值得旅
行的城市。他认为这样的自驾游很有意义,能够一次游历两个值得旅行的城市,并且能够
享受沿途风光。
由于小 h 是航空公司总裁的外甥的高中同学的大表弟的大学同学,因此他可以从 C 国
出发飞往 J 国的任何一个城市而不需要花钱,换言之,他可以从 J 国的任何一个国家出
发。方案很多,小 h 不知道哪个方案才是最省钱的方案,请问你能帮帮他吗?
题解:原题QwQ,二进制分组+最短路
对于每个被标记的点都跑一遍dij,然后在其它被标记的点中取min,复杂度 O(k*(n+m)logn)
对于暴力的优化:我们可以对这k个标记点进行二进制分组,分为两组,每次从set1向set2跑最短路取min,
再从set2向set1跑一遍最短路取min,因为若存在两个点之间的最短路为最小值,这两个点的下标的二进制
位一定有一位不一样,从而不被分在同一个组里,正确性被证明,这样只需要跑logk次即可。
复杂度 O(logk*(n+m)logn)
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<queue> #define maxn 100010 #define INF 2147483647 using namespace std; struct node { int ed,len,nxt; }; node edge[maxn*5]; int n,m,k,first[maxn],cnt,dis[maxn]; int love[maxn]; int set1_cnt,set2_cnt; int set1[maxn],set2[maxn]; bool vis[maxn]; inline void add_edge(int s,int e,int d) { cnt++; edge[cnt].ed=e; edge[cnt].len=d; edge[cnt].nxt=first[s]; first[s]=cnt; return; } inline void dijkstra() { priority_queue < pair <int,int> > heap; for(register int i=1;i<=n;++i) dis[i]=INF,vis[i]=false; for(register int i=1;i<=set1_cnt;++i) { dis[set1[i]]=0; heap.push(make_pair(-dis[set1[i]],set1[i])); } while(!heap.empty()) { int p=heap.top().second; heap.pop(); if(vis[p]) continue; vis[p]=true; for(register int i=first[p];i;i=edge[i].nxt) { int e=edge[i].ed; int d=edge[i].len; int newd=dis[p]+d; if(newd<dis[e]) { dis[e]=newd; heap.push(make_pair(-dis[e],e)); } } } return; } inline void dijkstra_2() { priority_queue < pair <int,int> > heap; for(register int i=1;i<=n;++i) dis[i]=INF,vis[i]=false; for(register int i=1;i<=set2_cnt;++i) { dis[set2[i]]=0; heap.push(make_pair(-dis[set2[i]],set2[i])); } while(!heap.empty()) { int p=heap.top().second; heap.pop(); if(vis[p]) continue; vis[p]=true; for(register int i=first[p];i;i=edge[i].nxt) { int e=edge[i].ed; int d=edge[i].len; int newd=dis[p]+d; if(newd<dis[e]) { dis[e]=newd; heap.push(make_pair(-dis[e],e)); } } } return; } int main() { int t; scanf("%d",&t); while(t--) { memset(edge,0,sizeof(edge)); memset(first,0,sizeof(first)); cnt=0; scanf("%d%d%d",&n,&m,&k); for(register int i=1;i<=m;++i) { int s,e,d; scanf("%d%d%d",&s,&e,&d); add_edge(s,e,d); } int ans=2147483647; for(register int i=1;i<=k;++i) scanf("%d",&love[i]); for(register int i=0;(1<<i)<=k;++i) { set1_cnt=0; set2_cnt=0; for(register int j=1;j<=k;++j) { if(((j>>i)&1)==0) set1[++set1_cnt]=love[j]; else set2[++set2_cnt]=love[j]; } dijkstra(); for(register int j=1;j<=set2_cnt;++j) ans=min(ans,dis[set2[j]]); dijkstra_2(); for(register int j=1;j<=set1_cnt;++j) ans=min(ans,dis[set1[j]]); } printf("%d\n",ans); } return 0; }
T3
Description
有一棵 n 个点的树,每个点上有一个多重集。每次修改,会选择两个点 x 和 y,然后在
这两个点的最短路径上的的每个点(包括首尾两个点)的多重集都加入一个数 z。经过 m 次
操作后,树上每个点的权值定义为这个点上的多重集的众数。如果众数有多个,则取最小的
众数。
问:m 次操作后,每个点的权值分别为多少。
Round9:P150 出题人:ZHX
T1
Description
众所周知,小葱同学擅长计算,尤其擅长计算组合数,但这个题和组合数没
什么关系。
小葱同学为了庆祝题目套数突破150,小葱同学学习了凯撒加密算法。凯撒
加密算法是有一个字符串和一个数字加密串,我们不断书写数字加密串使之与字
符串对齐,然后对应位相加之后即可得到加密的结果。例如,如果给定的字符串
是 abcdz,而加密串是 123 的话,那么我们有:
abcdz
+12312
=bdfeb
现在给定字符串𝑠,数字串𝑛,问用𝑛对𝑠进行𝑘次加密操作之后得到的结果是多少。
题解:简单的模拟,只要对每个位进行加减操作即可。
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define maxn 100010 using namespace std; long long k; int num[maxn]; char s_num[maxn],s[maxn]; int main() { freopen("crazy.in","r",stdin); freopen("crazy.out","w",stdout); scanf("%lld",&k); k=k%26; scanf("%s",s+1); scanf("%s",s_num+1); int len_s=strlen(s+1),len_num=strlen(s_num+1); for(register int i=1;i<=len_num;++i) num[i]=(int)(s_num[i]-'0'); for(register int i=len_num+1;i<=len_s;++i) { if(i%len_num==0) num[i]=num[len_num]; else num[i]=num[(i%len_num)]; } char up='z'; char down='a'; for(register int i=1;i<=len_s;++i) { int tmp=(int)((num[i]*k)%26); if(tmp>((int)(up-s[i]))) { tmp-=((int)up-s[i]); s[i]=(char)(((int)down)+tmp-1); } else s[i]=(char)(((int)s[i])+tmp); printf("%c",s[i]); } return 0; }
T2
小葱同学为了庆祝题目套数突破150,小葱同学自创了概率加密算法。现在
小葱同学有一个𝑁位的密码,密码的每一位都是1 − 𝑀中的一个数。现在小葱自
创的随机加密算法会给你𝑀个数𝑥𝑖,代表每次进行加密的时候,所有为𝑖的为都会
变成𝑥𝑖,而当𝑁位的密码全部变成和它一开始𝑁位一样之后,小葱同学的加密算
法也就停止了。所以,给定这个密码,然后求需要进行多少次加密是一个非常困
难的问题。为了简化这个问题,现在小葱假定我们并不知道输入的密码,输入的
密码是一个随机的密码,即总共𝑀^𝑁种可能性每种可能性的概率为𝑀^−𝑁。小葱同
学想要知道,在这种情况下,这个随机密码期望需要多少次能够完成加密操作。
题解:对于80分居然可以预处理每个数字变化多少次变回原来的数字,m^ndfs枚举
全排列找最小公倍数水过,正解是容斥原理

浙公网安备 33010602011771号