11 分球 解题日期:250206 解题用时:34min 题目来源:蓝桥云课题库 题目难度:简单 题目标签:数学,排列组合
题意整理 ![[Pasted image 20250206162600.png]]
解题思路 高中数学排列组合,第一反应隔板法。 将n个球和k-1个隔板进行排序,总数为n+k-1 组合数公式为C(m,r)=m!/r!(m-r)! 此时m=n+k-1;r=k-1; 但是后来尝试之后发现这道题目有很多坑。比如整数除法。 将res存为double之后,最后不能使用cout输出。一定要使用printf。 #### AC代码1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 #include <iostream> using namespace std;double factor (int n) { int k=n; double res=1 ; while (k>=1 ) { res*=k; k--; } return res; } int main () { int n,k; cin>>n>>k; double res=factor (n+k-1 )/factor (k-1 ); res/=factor (n); printf ("%.0f" ,res); }
12 购物车里的宝贝 解题日期:250215 解题用时:9min 题目来源:蓝桥题库 题目难度:简单 题目标签:位运算
题意整理 输入一个整数n,代表集合中元素的数目,现在问集合中的元素能否被划分成两个异或和相等的集合。
解题思路 能分成两个异或和相等的集合,即整体集合的异或和等于0.
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> using namespace std;int main () { int n; cin>>n; int a[100010 ]; cin>>a[0 ]; int count=a[0 ]; for (int i=1 ;i<n;i++){ cin>>a[i]; count=count^a[i]; } if (count==0 ){ cout<<"YES" ; } else { cout<<"NO" ; } return 0 ; }
13 消灭卡片 解题日期:250215 解题用时:230min 题目来源:蓝桥题库 题目难度:简单 题目标签:思维,数学,算法赛
题意整理 一共t组测试数据。每个测试数据包含n张需要消灭的卡片。每次可以消灭3张或者5张卡片,要用最少的行动次数消灭所有卡片。如果不能消灭则输出-1,如果可以消灭则输出最少次数。
解题思路 找规律。0~12注意8和11特例,其他全部n/5或者n/3即可。12以上的全部都可以表示,按照n%5的结果分成五类,简单计算讨论即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 #include <iostream> using namespace std; void solve () { int n; cin>>n; if (n<12 ){ int count=0 ; if (n%5 ==0 ){ count=n/5 ; cout<<count<<endl; return ; } if (n%3 ==0 ){ count=n/3 ; cout<<count<<endl; return ; } if (n%5 ==3 ){ count=n/5 +1 ; cout<<count<<endl; return ; } if (n==11 ){ count=3 ; cout<<count<<endl; return ; } cout<<-1 <<endl; return ; } else { int count=0 ; if (n%5 ==0 ){ count=n/5 ; } if (n%5 ==1 ){ count=n/5 +1 ; } if (n%5 ==2 ){ count=n/5 +2 ; } if (n%5 ==3 ){ count=n/5 +1 ; } if (n%5 ==4 ){ count=n/5 +2 ; } cout<<count<<endl; return ; } } int main () { int T; cin>>T; while (T--){ solve (); } return 0 ; }
14 k倍区间 解题日期:250215 解题用时:50min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,暴力,省赛。
题意整理 输入n,k,序列长度为n,如果其中一段连续子序列之和为K的倍数,就称这个区间 [ i , j ] 为K倍区间。
解题思路 直接暴力三重循环会运行超时,需要优化。 原先运行超时的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> using namespace std;int main () { int n,k; cin>>n>>k; int a[100010 ]; for (int i=0 ;i<n;i++){ cin>>a[i]; } int count=0 ; for (int i=0 ;i<n;i++){ for (int j=i;j<n;j++){ int cotemp=0 ; for (int m=i;m<=j;m++){ cotemp+=a[m]; } if (cotemp%k==0 )count++; } } cout<<count; return 0 ; }
想一下当两个数除以K的余数相同时,将他们相减之后是不是能被K整除(如:k=3,a1=4,b=7),我们会惊奇的发现是可以的,利用这个技巧,我们可以在求前缀和的时候判断一下这个前缀区间模上K的余数,并计数(cnt[]),然后再想一下,我们用前缀和求任意一个区间是怎么求得?这样当我们再在判断余数的时候,加上之前也是这个余数的前缀区间的集合数量,因为只要我这个有和前面任何一个余数相同,都能得到一个被K整除的区间(并且还不一样),利用这个我们可得到优化。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> using namespace std;const int N=100010 ;long long a[N];int cnt[N];int main () { int n,m; cin>>n>>m; cnt[0 ]=1 ; long long res=0 ; for (int i=1 ;i<=n;i++){ scanf ("%d" ,&a[i]); a[i]+=a[i-1 ]; res+=cnt[a[i]%m]; cnt[a[i]%m]++; } cout<<res<<endl; return 0 ; }
15 分巧克力 解题日期:250215 解题用时:50min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,省赛,二分
题意整理 共有N块巧克力,输入每一块的长和宽,现在需要将其分成k块,每块都是大小相等的正方形,求最大边长。
解题思路 先确定每一块巧克力可以分成的数量是(a/m)* (b/m),根据这个可以枚举出来结果。再使用二分算法优化,初始最短为1,最长为10000,对于确定的边长计算出可以分成的总数,与k进行判断比较,如果符合条件就往大取,不符合往小取。最后取r即为答案。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <iostream> using namespace std;const int N = 100010 ;int n,k;int h[N],w[N];bool check (int mid) {int res = 0 ;for (int i = 0 ;i < n;i++) { res += (h[i]/mid) * (w[i]/mid); if (res >= k) return true ; } return false ; } int main () { scanf ("%d%d" ,&n,&k); for (int i = 0 ;i < n;i++) scanf ("%d%d" ,&h[i],&w[i]); int l = 1 ,r = 1e5 ; while (l < r){ int mid = l + r + 1 >> 1 ; if (check (mid)) l = mid; else r = mid - 1 ; } printf ("%d\n" ,r); return 0 ; }
16 拉马车 解题日期:250216 解题用时:40min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,模拟,省赛
题意整理 马拉车纸牌游戏,过程如你熟悉。输入A和B的初始牌组,求最后赢家的牌组,如果不能分出胜负,则输出-1
解题思路 直接模拟,难点是字符串指针,以及栈数据结构的使用。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <bits/stdc++.h> using namespace std; bool a[128 ]; int main () { string A,B; cin>>A>>B; stack<char > S; S.push (A[0 ]); a[A[0 ]-0 ]=1 ; A.erase (0 ,1 ); bool flag=1 ; int times=0 ; while (A.length () && B.length () && times<10000 ){ string* sp=flag?&B:&A; char tmp=(*sp)[0 ]; S.push (tmp); sp->erase (0 ,1 ); if (a[tmp-0 ]==0 ) { a[tmp-0 ]=1 ; flag = !flag; } else { *sp += S.top (); S.pop (); while (S.top ()!=tmp){ *sp += S.top (); a[S.top ()-0 ] = 0 ; S.pop (); } *sp += S.top (); a[S.top ()-0 ] = 0 ; S.pop (); } times++; } if (times>=10000 ) return -1 ; if (A.length ()) cout<<A; else cout<<B; return 0 ; }
17 分考场 解题日期:250216 解题用时:45min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,搜索,国赛
题意整理 n个人分考场,两两相互认识不能在同一考场,输入相互认识的信息,求最少需要多少考场。
解题思路 使用深度优先搜索即可。
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> using namespace std;const int N = 110 ;int a[N][N];int p[N][N];int num = N;int n, m;void dfs (int x, int room) { if (room >= num)return ; if (x > n) { num = min (num, room); return ; } int j, k; for (j = 1 ; j <= room; j++) { k = 1 ; while (p[j][k] && !a[x][p[j][k]]) k++; if (p[j][k] == 0 ) { p[j][k] = x; dfs (x + 1 , room); p[j][k] = 0 ; } } p[room + 1 ][1 ] = x; dfs (x + 1 , room + 1 ); p[room + 1 ][1 ] = 0 ; } int main () { scanf ("%d%d" , &n, &m); for (int i = 0 ; i < m; i++) { int u, v; scanf ("%d%d" , &u, &v); a[u][v] =a[v][u]= 1 ; } dfs (1 , 1 ); printf ("%d" , num); return 0 ; }
18 合根植物 解题日期:250217 解题用时:30min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,并查集,国赛
题意整理 种植园中共有m* n棵合根植物,连根则合为一颗植物,输入m,n,以及k组数据表示a与b连根,问共有多少颗合根植物
解题思路 并查集模板题
并查集
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> using namespace std;const int N=1000010 ;int p[N];int find (int x) { if (p[x]!=x)p[x]=find (p[x]); return p[x]; } int main () { int n,m,k; cin>>n>>m>>k; for (int i=1 ;i<=n*m;i++){ p[i] = i; } for (int i=0 ;i<k;i++){ int a , b; scanf ("%d%d" ,&a,&b); int pa = find (a), pb = find (b); if (pa ! = pb) p[pa] = pb; } int res=0 ; for (int i=1 ;i<=n*m;i++){ if (p[i]==i) res++; } cout<<res<<endl; return 0 ; }
19 区间移位 解题日期:250217 解题用时:45min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,枚举,国赛,二分
题意整理 数轴上n个闭区间,已知区间长度之和至少又10^4 ,移动区间使其并集覆盖[0,10^4],找到一种方法使移动距离最大的区间的移动距离最小。
解题思路 不用关心区间怎么移动。只要去寻找最小的能满足覆盖0~10000的移动距离
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 #include <bits/stdc++.h> using namespace std;struct Node { int a; int b; }; int n;vector<Node> nv; bool ngreater (Node a,Node b) { return a.b < b.b; } bool check (int mid) { int mr = 0 ; vector<Node> temp (nv) ; while (true ) { bool flag = false ; for (int i = 0 ;i < temp.size ();i++) { Node node = temp[i]; int na = node.a, nb = node.b; int len = nb - na; if (na - mid <= mr && mr <= nb + mid) { flag = true ; if (na + mid >= mr) mr += len; else mr = nb + mid; temp.erase (temp.begin () + i); break ; } } if (mr >= 20000 || !flag) break ; } return mr >= 20000 ; } int main () { cin >> n; for (int i = 0 ;i < n;i++) { int a, b; cin >> a >> b; nv.push_back ({ a * 2 ,b * 2 }); } int l = 0 , r = 20000 ,mid; sort (nv.begin (), nv.end (), ngreater); while (r >= l) { mid = (l + r) / 2 ; if (check (mid)) r = mid - 1 ; else l = mid + 1 ; } double m = ((double )r + 1 ) / 2 ; cout << m; return 0 ; }
20 数组操作 解题日期:250217 解题用时:26min 题目来源:蓝桥杯真题 题目难度:中等 题目标签:2017,线段树,国赛
题意整理 给出一个长度为n的数组,从1到n标号,需要维护m个操作。 l到r都加上d l1到r1的位置赋值成l2到r2的值 求出数组中下标l到r的位置的和
解题思路 线段树模板题目
线段树
AC代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <stdio.h> #define int long long int v[100005 ];inline int read () { int x=0 ;char c=getchar (); while (c>='0' &&c<='9' ) { x=(x<<3 )+(x<<1 )+c-'0' ;c=getchar (); } return x; } signed main () { int m=read (),n=read ();m=read (); for (int i=1 ;i<=n;i++) v[i]=read (); int a,b,c,d,op; while (m--) { op=read (); a=read ();b=read (); if (op==2 ) { c=read ();d=read (); if (a<c) { for (int i=a;i<=b;i++) v[i]=v[c++]; } else { for (int i=b;i>=a;i--) v[i]=v[d--]; } } else if (op==1 ) { c=read (); for (int i=a;i<=b;i++) v[i]+=c; } else { int sum=0 ; for (int i=a;i<=b;i++) sum+=v[i]; printf ("%lld\n" ,sum); } } return 0 ; }