第十二届蓝桥杯省赛第二场C/C++B组题解
成绩出来了,三题填空,三题半大题,弱省省一中上,要是E题没有看错权重就省一头了呀
题目 | 答案 | 分值 |
---|---|---|
A: 求余 | 1 | 5 |
B: 双阶乘 | 59375 | 5 |
C: 格点 | 15698 | 10 |
D: 整数分解 | 691677274345 | 10 |
E: 城邦 | 4046 | 15 |
代码:
#include
using namespace std;
int main(){
cout<< 2021%20 <<endl;
return 0;
}
//1
分析:高位上的数字对结果没有影响,取余截掉
代码:
#include
using namespace std;
int main(){
int num = 1;
for(int i =2021;i>0;i-=2) num = (num * i) %1000000;
cout<< num % 100000 <<endl;
return 0;
}
//59375
分析: 根据题意,枚举所有可能符合的坐标,进行判断
代码:
#include
using namespace std;
int main(){
int res = 0;
for(int i =1;i<=2030;i++){
for(int j =1;j<=2030;j++){
if(i * j <=2021) res++;
}
}
cout<< res <<endl;
return 0;
}
//15698
暴力枚举所有和为2021的五个正整数组合,再根据五个数的重复数排列组合
#include
using namespace std;
#define ll long long
int main(){
long long res = 0;
int n =2021;
for(int a = 1;a<=500;a++){
for(int b = a;b<=1000;b++){
for(int c = b;c<=1500;c++){
for(int d = c;d<=2000;d++){
int e = n - a - b - c - d, t = 0;
if(e >= d){
//五个相等
if(a==e) t =1;
//四个相等
else if((a==d) || (b==e)) t =5;
//三个相等 + 两个相等
else if((a==c && d == e) || (a==b && c==e)) t =10;
//三个相等
else if((a==c) || (b==d) || (c==e)) t= 20;
//两对相等
else if((a==b && c==d) || (a==b && d==e) || (b==c && d ==e)) t= 30;
//一对相等
else if(a==b || b==c || c==d || d==e) t = 60;
//全不相等
else t = 120;
}
res += t;
}
}
}
}
cout<< res <<endl;
return 0;
}
//691677274345
三重循环枚举三个数,差是m,和为m的两个正整数可能是m-1种
#include
using namespace std;
int main()
{
ll ans = 0;
int n = 2021;
for(int i = 1;i < n; ++i) {
for(int j = 1;j < n; ++j) {
for(int k = 1;k < n; ++k) {
int m = 2021 - i - j - k;
if(m <= 1) break;
ans += m - 1;
}
}
}
cout<< ans <<endl;
return 0;
}
1-2021,取五个数的和是2021的可能数
d p [ i ] [ j ] dp[i][j] dp[i][j]表示 i i i个数和为j的可能数
k k k表示 d p [ i − 1 ] [ j − k ] dp[i-1][j-k] dp[i−1][j−k]加上一个数 k k k,就是 d p [ i ] [ j ] dp[i][j] dp[i][j]的所有可能
d p [ i ] [ j ] = { d p [ i ] [ j ] + d p [ i − 1 ] [ j − k ] ( j > k ) 0 dp[i][j] = \begin{cases} dp[i][j] +dp[i-1][j-k](j>k)\\0 \end{cases} dp[i][j]={dp[i][j]+dp[i−1][j−k](j>k)0
代码:
#include
using namespace std;
#define ll long long
int main(){
ll dp[6][2022];
memset(dp, 0, sizeof dp);
for(int i = 1;i<2022;i++) dp[1][i] = 1;
for(int i =2;i<=5;i++)
for(int j =1; j<2022;j++)
for(int k = 1;k<2022;k++){
if(j-k > 0) dp[i][j] += dp[i-1][j-k];
}
cout<< dp[5][2021];
return 0;
}
//691677274345
C(2,6)
#include
using namespace std;
#define n 20210509
#define ll long long
ll dp[20210519];
int main() {
cout<< 1ll*2020*2019*2018*2017/4/3/2<<endl;
return 0;
}
//691677274345
分析:构建邻接矩阵,最小生成树套模板(prim)
代码:
#include
using namespace std;
#define maxn 2030
#define INF 0x3f3f3f3f
int e[maxn][maxn];
int cost[maxn];
bool used[maxn];
int V = 2021;
//prim
int prim(){
for(int i =1;i<=2021;i++){
cost[i] = INF;
used[i] = false;
}
cost[1] = 0;
int res = 0;
while (1)
{
int v = -1;
for(int u = 1;u<=V;u++){
if(!used[u] && (v==-1 || cost[u] < cost[v])) v = u;
}
if(v == -1) break;
used[v] = 1;
res += cost[v];
for(int u = 1;u<=V;u++){
cost[u] = min(cost[u], e[v][u]);
}
}
return res;
}
//获取权重
int get(int a, int b){
int res = 0;
while(a || b){
if(a%10 != b%10) res+=a%10 + b%10;
a/=10, b/=10;
}
return res;
}
void solve(){
//邻接矩阵
memset(e, 0, sizeof e);
for(int i =1;i<=2021;i++)
{
for(int j =1;j<=2021;j++)
{
if(i == j) continue;
e[i][j] = e[j][i] = get(i , j);
}
}
prim();
cout<< prim() <<endl;
}
int main(){
solve();
return 0;
}
//4046
分析:根据题意,求各位的数字,进行判断
代码:
#include
#include
using namespace std;
#define maxn 10
int a[maxn];
int main(){
for(int i =0;i<5;i++) cin>>a[i];
int res = 0;
for(int i=0;i<5;i++){
int q = a[i] /1000;
int b = a[i] %1000 / 100;
int s = a[i] %100 / 10;
int g = a[i] %10;
if(q == s && g == b +1) {
res ++;
}
}
cout<< res;
return 0;
}
分析:暴力枚举,数据规模小(1 ≤ n ≤ 10000)
代码:
#include
using namespace std;
int main(){
int n;
cin >> n;
int res = 0;
for(int i =1;i<n;i++){
if( (i*i%n) < (n /2.0)) res++;
}
cout<< res;
return 0;
}
分析:参考大佬的题解。。
对n进行质因数分解,将奇数个的所有质因数的乘积就是答案。
举例子:对某个数质因数分解的结果是:2 2 2 3 3 3,那么这个数乘上2*3就是完全平方数
举例子:某个数的质因数分解的结果是:2 2 3 3 4 4, 那么这个数本身就是完全平方数,答案是1;
代码:
#include
using namespace std;
#define ll long long
int main(){
ll n;
cin>>n;
ll res =1;
for(int i =2;i<=1000010;++i){
if(n<2) break;
ll t = 0;
while(n%i==0){
++t;
n/=i;
}
if(t%2==1) res *= i;
}
if(n > 1) res *= n;
cout << res;
return 0;
}
分析:
代码要模拟的功能总结:枚举所有任务,对于当前每个任务,消耗算力并将该算力倒计时,直到任务结束返回算力(当前任务消耗d算力c秒)。
由于时间的数据范围10^9,枚举所有的时间会超时。怎么进行算力倒计时结束后将算力恢复,决定了这道题的时间复杂度
优先队列小顶堆维护任务占用的算力,算力释放的时间 (a+c) 为优先级。每次分配任务前,先释放算力,如果足够分配当前任务,将该任务消耗的算力压入优先队列。
时间复杂度O(m*log(m)),应该能过全部数据吧。
代码:
#include
using namespace std;
#define maxn 200010
int n, m;
int arr[maxn];
int a, b, c, d;
struct Node
{
int endTime, id , val;
bool operator< (const Node &node)const {
return endTime > node.endTime;
}
};
priority_queue<Node> q;
//释放算力
void getd(){
while(!q.empty()){
Node t= q.top();
if(t.endTime > a) break;
q.pop();
int i =t.id, v = t.val;
arr[i] += v;
}
}
//消耗算力
void task(){
getd();
if(arr[b] >= d){
q.push({a+c, b ,d});//算力进入恢复队列
arr[b] -= d;
cout<< arr[b];
}else{
cout<<"-1";
}
}
int main(){
cin>>n>>m;
memset(arr, 0 , sizeof arr);
for(int i =1;i<=n;i++) cin>>arr[i];
while(m--){
cin>> a>> b >>c>>d;
task();
if(m>0) cout<<endl;
}
return 0;
}
每一行只受限于上两行的状态
#include
using namespace std;
const int N = 110, M = 1<<6,K = 21, MOD = 1e9+7;
int n, m ,k;
int dp[N][M][M][K];
#define ll long long
int getCnt(int num){
int res = 0;
while (num)
{
res ++;
num &= (num-1);
}
return res;
}
int main(){
cin >> n >> m >> k;
dp[0][0][0][0] = 1;
for(int i =1;i<=m;i++){
for(int a = 0;a< 1<<n;a++){
for(int b = 0; b< 1<<n;b++){
if(a & (b << 2) || b & (a << 2)) continue;
for(int c = 0;c < 1<<n; c++){
if(b & (c << 2) || c & (b << 2)) continue;
if(a & (c << 1) || c & (a << 1)) continue;
int t = getCnt(a);
for(int j = t;j<=k;j++){
dp[i][a][b][j] += dp[i-1][b][c][j-t] % MOD;
}
}
}
}
}
ll res = 0;
for(int i =0;i<1<<n;i++)
for(int j =0;j< 1<<n;j++)
res += dp[m][i][j][k]%MOD;
cout<< res %MOD <<endl;
return 0;
}
有错的地方请指正
参考视频讲解:第十二届蓝桥杯(第二场)C++ B组讲解
参考博客:第十二届蓝桥杯大赛软件赛省赛第二场题解
参考视频讲解:第十二届蓝桥杯C++ B组第二场省赛题目讲解