测评(民间数据):http://oj.daimayuan.top/course/18/problems
第十三届蓝桥杯C/C++ B组答案+思路
A 九进制转十进制(100%)
思路:
类比2进制, 最低位(最右边)为20,第二位为21
同理此题答案为 2*90+2*91+0*92+2*93=1478
答案:
1478
B 顺子日期(100%)
思路:
(猜题意)连续的3个上升的是顺子(具体看题目20221023中的210),还有就是0算在里面
不愿意想就直接无脑的写个代码
答案:
14
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool judge(int y,int m,int d){
vector<int> v;
v.push_back(2),v.push_back(0),v.push_back(2),v.push_back(2);
if(m>=10) v.push_back(1);
else v.push_back(0);
v.push_back(m%10);
if(d >= 10) v.push_back(d/10);
else v.push_back(0);
v.push_back(d%10);
int now=1;
for(int i=1;i<v.size();++i){
if(v[i]==v[i-1]+1) now++;
else now=1;
if(now>=3) return true;
}
return false;
}
int main()
{
int ans=0;
for(int i=1;i<=12;++i){
for(int j=1;j<=day[i];++j){
if(judge(2022,i,j)) ans++;
}
}
cout << ans << endl;
return 0;
}
C 刷题统计(100%)
【样例输入1】
10 20 99
【样例输出1】
8
【评测用例规模与约定】
对于 50% 的评测用例,1 ≤ a, b, n ≤ 106
对于 100% 的评测用例,1 ≤ a, b, n ≤ 1018
.
思路:
首先算出一周能刷多少题 5*a+2*b
然后算多出来的花几天能刷完
5e18+2e18=7e18 < long long(9223372036854775807)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
int main()
{
ll a,b,n;//注意用long long
cin >> a >> b >> n;
ll ans=0;
ll week=n/(5*a+2*b);
ans+=week*7;
n-=week*(5*a+2*b);
for(int i=1;i<=5;++i){
if(n<=0) break;
n-=a;ans++;
}
if(n > b) ans+=2;
else if(n > 0) ans+=1;
cout << ans << endl;
return 0;
}
D 修剪灌木(100%)
【样例输入】
3
【样例输出】
4
2
4
【评测用例规模与约定】
对于 30% 的数据,N ≤ 10.
对于 100% 的数据,1 < N ≤ 10000.
思路:
刚开始全是0,每天傍晚前长高1,傍晚后爱丽丝来修剪,也就是说爱丽丝剪完第 i 个灌木后可能会去 i 的左边,也可能去 i 的右边,然后返回来,所以他长的最长高度就是左右两边数目中的取更大的*2 就是答案了
在比赛的时候看着好像是左右对称且每个是前面一个减2(但是要注意1的特判)
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
int A[N];
int main()
{
int n;
cin >> n;
if(n==1){cout << 1 << endl;return 0;}
A[1]=A[n]=(n-1)*2;
for(int i=2;i<=n;++i){
if(A[i]!=0) break;
A[i]=A[n-i+1]=A[i-1]-2;
}
for(int i=1;i<=n;++i){
cout << A[i] << endl;
}
return 0;
}
E X进制减法(100%)
【样例输入】
11
3
10 4 0
3
1 2 0
【样例输出】
94
【样例说明】
当进制为:最低位 2 进制,第二数位 5 进制,第三数位 11 进制时
减法得到的差最小。
此时 A 在十进制下是 108,B 在十进制下是 14,差值是 94。
【评测用例规模与约定】
对于 30% 的数据,N ≤ 10; Ma, Mb ≤ 8.
对于 100% 的数据,2 ≤ N ≤ 1000; 1 ≤ Ma, Mb ≤ 100000; A ≥ B.
思路:
首先很多同学不懂 321 怎么转换成的 65
我们正着推不好推那就反着推看看65—>321
最低位的进制是2进制,也就是满2进1所以65/2=32余1(进32余1)
然后第二位为10进制,满10进1 所以32/10=3余2(进3余2)
最后以为为8进制 进上来3直接填上就好了
.
所以可以倒推出321->65 即每一位乘上一位的进制
即(3*10+2)*2+1=65
.
最后题目给出A>=b,所以不用考虑负数的情况
猜结论)
如果进制尽可能地小,则差值更小(为什么呢)贪心猜测:如果到第k位前k-1位都是按照同样的进制运算的A为ansA,B为ansB,且相应A,B此位为a1,b1。则此处的A运算为ansA*k+a1,B运算为ansB*k+b1 且已知ansA >=ansB 则k越小差值越小。
不知道对不对 而且比赛的时候忘记可能会存在前导零了QAQ
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
const int mod=1e9+7;
int k[N];
int main()
{
int N,Ma,Mb;
cin >> N;
cin >> Ma;
vector<int> A(Ma);
for(int i=0;i<Ma;++i){
cin >> A[i];
}
cin >> Mb;
vector<int> B(Mb);
for(int i=0;i<Mb;++i){
cin >> B[i];
}
//对齐
reverse(B.begin(),B.end());
reverse(A.begin(),A.end());
while(A.size()!=B.size()){
if(A.size() < B.size()) A.push_back(0);
else B.push_back(0);
}
reverse(B.begin(),B.end());
reverse(A.begin(),A.end());
int n=A.size();
ll ans1=0,ans2=0;
for(int i=0;i<n;++i){
int now=max(A[i],B[i]);
if(now==0) k[i]=2;
else k[i]=now+1;
}
k[n]=1;
for(int i=0;i<n;++i){
ans1=(ans1+A[i])*k[i+1]%mod;
}
for(int i=0;i<n;++i){
ans2=(ans2+B[i])*k[i+1]%mod;
}
cout << (ans1-ans2+mod)%mod;
return 0;
}
F 统计子矩阵(70%)
【样例输入】
3 4 10
1 2 3 4
5 6 7 8
9 10 11 12
【样例输出】
19
【样例说明】
满足条件的子矩阵一共有 19,包含:
大小为 1 × 1 的有 10 个。
大小为 1 × 2 的有 3 个。
大小为 1 × 3 的有 2 个。
大小为 1 × 4 的有 1 个。
大小为 2 × 1 的有 3 个。
【评测用例规模与约定】
对于 30% 的数据,N, M ≤ 20.
对于 70% 的数据,N, M ≤ 100.
对于 100% 的数据,1 ≤ N, M ≤ 500; 0 ≤ Ai j ≤ 1000; 1 ≤ K ≤ 250000000.
思路:
QAQ只会前缀和然后暴力骗分
首先要用二维前缀和
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
然后遍历每个点往左上角看有多少个子矩阵满足条件
(只能骗70%的分)
批注:最多只能过前70%的样例,如果有更好的方法欢迎在评论区留言
答案:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e3+10;
int A[N][N];
int sum[N][N];
int getsum(int i,int j,int k,int l){
return sum[i][j]-sum[i][l-1]-sum[k-1][j]+sum[k-1][l-1];
}
int main()
{
int n,m,K;
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
scanf("%d",&A[i][j]);
}
}
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+A[i][j];
}
}
int ans=0;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
for(int k=1;k<=i;++k){
for(int l=1;l<=j;++l){
if(getsum(i,j,k,l) <= K) ans++;
}
}
}
}
cout << ans << endl;
return 0;
}
G 积木画(100%)
【样例输入】
3
【样例输出】
5
【评测用例规模与约定】
对于所有测试用例,1 ≤ N ≤ 10000000.
思路(考场思路):
- dp
考场上的思路:
答案:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e7+10;
const int mod=1e9+7;
int dp[N][4];
int main()
{
int n;
cin >> n;
dp[0][1]=1;
for(int i=1;i<=n;++i){
dp[i][1]=(dp[i][1]+dp[i-1][1])%mod;
dp[i][1]=(dp[i][1]+dp[i-1][2])%mod;
dp[i][1]=(dp[i][1]+dp[i-1][3])%mod;
if(i >= 2) dp[i][1]=(dp[i][1]+dp[i-2][1])%mod;
dp[i][2]=(dp[i-1][3])%mod;
if(i >= 2) dp[i][2]=(dp[i][2]+dp[i-2][1])%mod;
dp[i][3]=(dp[i-1][2])%mod;
if(i >= 2) dp[i][3]=(dp[i][3]+dp[i-2][1])%mod;
}
cout << dp[n][1];
return 0;
}
H 扫雷(0%)
【样例输入】
2 1
2 2 4
4 4 2
0 0 5
【样例输出】
2
【评测用例规模与约定】
对于 40% 的评测用例:0 ≤ x, y ≤ 109, 0 ≤ n, m ≤ 103, 1 ≤ r ≤ 10.
对于 100% 的评测用例:0 ≤ x, y ≤ 109, 0 ≤ n, m ≤ 5 × 104, 1 ≤ r ≤ 10
批注:不会,1分都没骗。。
I 李白打酒加强版(100%)
【样例输入】
5 10
【样例输出】
14
【样例说明】
如果我们用 0 代表遇到花,1 代表遇到店,14 种顺序如下:
010101101000000
010110010010000
011000110010000
100010110010000
011001000110000
100011000110000
100100010110000
010110100000100
011001001000100
100011001000100
100100011000100
011010000010100
100100100010100
101000001010100
【评测用例规模与约定】
对于 40% 的评测用例:1 ≤ N, M ≤ 10。
对于 100% 的评测用例:1 ≤ N, M ≤ 100。
思路:
(好像是dp)不过我选择骗分!!40%的1 ≤ N, M ≤ 10。 直接全排列看那个符合条件(220不大)
批注:最多只能过前40%的样例,如果有更好的方法欢迎在评论区留言
答案:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=1e6+10;
vector<int> v;
int ans=0;
void dfs(int nown,int nowm){
if(nown==0 && nowm==0){
int now=2;
v.push_back(0);
for(int i=0;i<v.size();++i){
if(v[i]==1) now*=2;
else now-=1;
if(now < 0){
v.pop_back();
return;
}
}
if(now==0)
ans++;
v.pop_back();
return;
}
if(nown > 0){
v.push_back(1);
dfs(nown-1,nowm);
v.pop_back();
}
if(nowm > 0){
v.push_back(0);
dfs(nown,nowm-1);
v.pop_back();
}
}
int main()
{
int n,m;
cin >> n>> m;
dfs(n,m-1);//最后一个必为花
cout << ans << endl;
return 0;
}
赛后补题记忆化dfs
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=2e2+10;
const int mod=1e9+7;
ll dp[N][N][N];//到第x个位置,花剩多少个可以用,到这里的价值是多少,的方案数
int n,m;//n个店 m个花
int dfs(int x,int nowm,int v){
if(v >= n+m) return 0;
if(dp[x][nowm][v]!=-1) return dp[x][nowm][v]%mod;
int res=0;
if(nowm>0) res=(res+dfs(x+1,nowm-1,v-1))%mod;
res=(res+dfs(x+1,nowm,2*v))%mod;
return dp[x][nowm][v]=res%mod;
}
int main()
{
cin >> n >> m;
for(int i=1;i<=n+m-1;++i){
for(int j=1;j<=m;++j){
for(int k=1;k<=n+m;++k){
dp[i][j][k]=-1;
}
}
}
dp[n+m][0][1]=1;//如果到第n+m个位置,手中的花剩下0个,且剩下1斗酒,就可行
cout << dfs(1,m-1,2);
return 0;
}
队友gzj的dp:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int128 __int128
typedef pair<int,int> PII;
const int N=2e2+10;
const int mod=1e9+7;
ll dp[N][N][N];//到第x个位置,花剩多少个可以用,到这里的价值是多少,的方案数
int n,m;//n个店 m个花
int main()
{
cin >> n >> m;
dp[0][m][2]=1;
for(int i=1;i<=n+m;i++){
for(int j=0;j<=m;j++){
for(int k=205;k>=0;k--){
dp[i][j][k]=(dp[i][j][k]+dp[i-1][j+1][k+1])%mod;
if(k%2==0)
dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k/2])%mod;
}
}
}
cout<<dp[n+m-1][1][1]%mod<<endl;
return 0;
}
J 砍竹子(100%)
【样例输入】
6
2 1 4 2 6 7
【样例输出】
5
【样例说明】
其中一种方案:
2 1 4 2 6 7
→ 2 1 4 2 6 2
→ 2 1 4 2 2 2
→ 2 1 1 2 2 2
→ 1 1 1 2 2 2
→ 1 1 1 1 1 1
共需要 5 步完成
【评测用例规模与约定】
对于 20% 的数据,保证 n ≤ 1000, hi ≤ 106。
对于 100% 的数据,保证 n ≤ 2 × 105, hi ≤ 1018。
思路:
(比赛的时候没写)看题目的公式1e18化为1也就不到10次,所以不用担心hi太大时间复杂度太高
用优先队列进行处理,将首先从大到小砍(说不定砍成的数和某个小的刚好挨着可以一起砍掉)
怎么说,,,思路感觉也不是很难,看代码吧不知道对不对
#include<bits/stdc++.h>
#include<time.h>
using namespace std;
#define ll long long
#define int128 __int128
#define random1(x,y) (rand()%(1ll*y-1ll*x+1ll)+1ll*x)
typedef pair<int,int> PII;
const int N=1e6+10;
struct node{
ll x,id;
bool operator < (const node& b)const{
if(x==b.x) return id < b.id;
else return x < b.x;
}
};
int getnum(ll a){
return (int)(sqrt(a/2+1));
}
priority_queue<node> q;
ll A[N];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i){
ll temp;
scanf("%lld",&temp);
q.push({temp,i});
}
/*
//把上面的删掉
srand( (unsigned)time( NULL ) );//这里
int n=200000;
for(int i=0;i<n;++i){
q.push({random1(1,10000000000000000),i});
}
clock_t stime = clock(); //开始计时
*/
ll ans=0;
while(q.top().x!=1){
node now=q.top();
q.pop();
int nowid=now.id;
ll nowx=now.x;
ans++;
q.push({getnum(now.x),nowid});
while(q.top().x==nowx){
node temp=q.top();
q.pop();
if(temp.id!=nowid-1){
ans++;
}
nowid=temp.id;
q.push({getnum(now.x),nowid});
}
}
cout << ans << endl;
// clock_t etime = clock(); //结束计时
// printf("running time is :%d ms\n", etime-stime);
return 0;
}
批注:如果有误或者某题有更好的思路,欢迎在评论区留言^_^