蓝桥杯模拟赛
快速幂
题目要求
参考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
| using namespace std; long long bigpow1(int a,int b) //递归实现 { if(b==0) return 1; if(b&1) return bigpow1(a,b/2)*bigpow1(a,b/2)*a; else return bigpow1(a,b/2)*bigpow1(a,b/2); } long long bigpow2(int a,int b) //二分实现 { int re=1,base=a; while(b!=0) { if(b&1) re*=base; base*=base; b>>=1; } return re; } long long bigpow3(int a,int b,int p) //二分取模 { int re=1,base=a%p; while(b!=0) { if(b&1) re*=base%p; base*=base%p; b>>=1; } return re; } int main() { int a,b,p; cin>>a>>b>>p; long long re=bigpow3(a,b,p); cout<<re<<endl; return 0; }
|
注意事项
给出了快速幂的递归实现,二分实现以及二分取模实现。
线段点和
题目要求
参考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
| using namespace std; int vis[10050],dian[50050]; struct node { int l,r; }e[10050]; bool cmp(node x,node y) { if(x.l==y.l) return x.r<y.r; else return x.l<y.l; } int main() { int n,m; cin>>n>>m; memset(vis,0,sizeof(vis)); memset(dian,0,sizeof(dian)); for(int i=1;i<=n;i++) { int x; cin>>x; dian[x]=1; } for(int i=1;i<=m;i++) cin>>e[i].l>>e[i].r; int ans=0,E; sort(e+1,e+1+m,cmp); for(int i=1;i<=m;i++) { int max=-INT_MAX; if(!vis[i]) { for(int j=e[i].l;j<=e[i].r;j++) { if(dian[j]) { int flag=1; for(int k=i+1;k<=m;k++) { if(j>=e[k].l&&j<=e[k].r) flag++; else break; } if(flag>max) { max=flag; E=j; } } } ans++; for(int j=i+1;j<=m;j++) { if(E>=e[j].l&&E<=e[j].r) vis[j]=1; else break; } } } cout<<ans<<endl; return 0; }
|
思路
对所有区间进行升序排序,若x值一样按y值的升序排列。从第一个区间开始遍历所有给出的点,若满足该区间则判断是否满足下一个区间,直到不满足为止。
计算并保留走的最远的点,把中间经历过的区间的vis至为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 28 29
| using namespace std; int dp[50],flag[50]; int main() { int n,m; cin>>n>>m; memset(flag,0,sizeof(flag)); memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++) { int x; cin>>x; flag[x]++; } if(!flag[1]) dp[1]=1; if(!flag[2]) dp[2]=1; for(int i=3;i<=n;i++) { if(flag[i]) continue; dp[i]=dp[i-1]+dp[i-2]; } cout<<dp[n]<<endl; return 0; }
|
思路
不考虑陷进的情况下,满足斐波拉契递推式dp[n]=dp[n-1]+dp[n-2]。dp[1]=dp[2]=1。考虑陷进的情况下只需把陷进处的dp值赋为0即可。
盾神与砝码称重
题目要求
参考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
| using namespace std; int n,m,w[25]; int dfs(int now,int id) { if(!now) return 1; if(now&&id==n+1) return 0; return dfs(now-w[id],id+1)||dfs(now,id+1)||dfs(now+w[id],id+1); } int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>w[i]; sort(w+1,w+1+n); for(int i=1;i<=m;i++) { int x; cin>>x; if(dfs(x,1)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
|
参考代码(优化剪枝)
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
| using namespace std; int n,m,w[25],sum[25]; int dfs(int now,int id) { if(!now) return 1; if(now&&id==0) return 0; if(abs(now)>sum[id]) return 0; return dfs(now-w[id],id-1)||dfs(now,id-1)||dfs(now+w[id],id-1); } int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>w[i]; sum[0]=0; sort(w+1,w+1+n); for(int i=1;i<=n;i++) sum[i]=sum[i-1]+w[i]; for(int i=1;i<=m;i++) { int x; cin>>x; if(dfs(x,n)) cout<<"YES"<<endl; else cout<<"NO"<<endl; } return 0; }
|
思路
暴力裸搜只能得50分,复杂度为3^n(放左 放右 不放)会爆。所以采用优化剪枝的方法,把砝码按质量大小升序排序后求出前缀和。从最大的砝码开始放,
加一个剪枝:若目前物体剩余的质量的绝对值仍大于剩余所有砝码的质量,返回0。
减格子
题目要求
参考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
| using namespace std; int num[N][N]; int tag[N][N] = {0}; int m, n; int r = 100; int bad(int i, int j) { if (i < 0 || i >= n || j < 0 || j >= m || tag[i][j] == 1) return 1; return 0; } void go(int i, int j, int k, int count) { if (bad(i, j) || count < num[i][j]) return; k++; if (count == num[i][j]) { if (r > k) r = k; return; } tag[i][j] = 1; count -= num[i][j]; go(i - 1, j, k, count); go(i + 1, j, k, count); go(i, j - 1, k, count); go(i, j + 1, k, count); tag[i][j] = 0; } int main() { int i, j; int half = 0; scanf("%d %d", &m, &n); for (i = 0; i < n; i++) for (j = 0; j < m; j++) { scanf("%d", &num[i][j]); half += num[i][j]; } if (half % 2 == 0 && half >= num[0][0] * 2) { half /= 2; go(0, 0, 0, half); } if (r == 100) r = 0; printf("%d", r); return 0; }
|
注意事项
深搜即可。