2022 第十三届蓝桥杯大赛软件赛省赛,C/C++ 大学B组题解
补题链接:地址
#include
using namespace std;
int main(){
cout<<2+2*9+2*9*9*9<<"\n";
return 0;
}
#include
using namespace std;
int days[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; //2022不是闰年
int main(){
int cnt = 0;
for(int month = 1; month <= 12; month++)
for (int day = 1; day <= days[month]; day++) {
string s = "2022";
if (month < 10) s += '0'+ to_string(month);
else s += to_string(month);
if (day < 10) s += '0' + to_string(day);
else s += to_string(day);
if(s.find("012") != s.npos || s.find("123") != s.npos){
cnt++;
}
}
cout<<cnt<<"\n";
return 0;
}
#include
using namespace std;
typedef long long LL; //开ll
int main(){
LL a, b, n; cin>>a>>b>>n;
LL c = a*5+b*2; //每周做的题数
LL day = n/c*7; //直接除
n = n%c;
while(n > 0){
day++;
if(day%7==6 || day%7==0)n -= b; //周末
else n -= a;
}
cout<<day<<"\n";
return 0;
}
#include
using namespace std;
int main(){
int n; cin>>n;
for(int i = 1; i <= n; i++)cout<<max(i-1,n-i)*2<<endl;
return 0;
}
题意:定义X进制表示每一位进制不同的数。给出两个X进制数A和B(规则相同,但是不知道规则,且最高N进制,最低2进制),求A-B的可能最小值。
思路:
因为AB的规则是一样的,所以A-B第i位的值其实已经确定了,就是给他们加个规则。
那必然是进制越小越好,最好是2进制。
如果都是2进制就不满足规则了,所以最小进制肯定是右边i+1上A和B的最大+1,不要再大了。
#include
using namespace std;
typedef long long LL;
const int mod = 1000000007, maxn = 1e5+10;
LL a[maxn], b[maxn];
int main(){
int n, an, bn; cin>>n>>an;
for(int i = an; i >= 1; i--)cin>>a[i];//1-n低位到高位
cin>>bn;
for(int i = bn; i >= 1; i--)cin>>b[i];
LL ans = 0, base = 1;
for(int i = 1; i <= an; i++){
LL w = max({a[i], b[i],1LL})+1;
ans = (ans+(a[i]-b[i])*base)%mod;
base = base*w%mod;
}
cout<<ans<<"\n";
return 0;
}
#include
using namespace std;
typedef long long LL;
const int maxn = 550;
LL a[maxn][maxn], b[maxn][maxn], ans;
int main(){
int n, m, k; cin>>n>>m>>k;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
cin>>a[i][j];
a[i][j] += a[i-1][j]+a[i][j-1]-a[i-1][j-1];//二维前缀和
}
}
for(int l = 1; l <= m; l++){
for(int r = l; r <= m; r++){
for(int i = 1, j = 1; i <= n; i++){ //双指针
while(j <= i && (a[i][r]-a[i][l-1]-a[j-1][r]+a[j-1][l-1])>k){
j++;
}
if(j <= i)ans += i-j+1;
}
}
}
cout<<ans<<"\n";
return 0;
}
#include
using namespace std;
typedef long long LL;
const int maxn = 1e7+10, mod = 1e9+7;
int f[maxn][4];
int main(){
int n; cin>>n;
f[0][3] = 1;
f[1][0] = 1; f[1][1] = 1; f[1][2] = 1; f[1][3] = 2;
for(int i = 2; i <= n; i++){
f[i][0]=(LL)(f[i-1][3])%mod;
f[i][1]=(LL)(f[i-1][0]+f[i-1][2])%mod;
f[i][2]=(LL)(f[i-1][1]+f[i-1][0])%mod;
f[i][3]=((LL)(f[i-1][1]+f[i-1][2])%mod+(LL)(f[i-1][3]+f[i-2][3])%mod)%mod;
}
cout<<f[n][0]<<endl;
return 0;
}
#include
using namespace std;
inline long long qpow(long long x){ return x * x; }
struct hsh {
size_t operator () (const pair<int,int> &a) const {
return a.first * 239 + a.second * 7;
}
};
unordered_map< pair<int,int>, int, hsh> mp;
unordered_map< pair<int,int>, int, hsh> rr;
long long ans = 0;
void dfs(int x, int y, int r){
for(int i = x-r; i <= x+r; i++){ //枚举半径范围内的所有点
for(int j = y-r; j <= y+r; j++){
if(qpow(i-x)+qpow(j-y) <= qpow(r)){
auto it = make_pair(i,j);
if(mp.count(it)){ //判断是不是雷
ans += mp[it];
mp.erase(it);
dfs(i,j,rr[it]); //递归爆炸
}
}
}
}
}
int main(){
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m; cin>>n>>m;
for(int i = 1; i <= n; i++){
int x, y, r; cin>>x>>y>>r;
auto pos = make_pair(x,y);
mp[pos]++;
rr[pos] = max(r, rr[pos]);
}
while(m--){
int x, y, r;
cin>>x>>y>>r;
dfs(x, y, r); //从这里开始爆炸
}
cout<<ans<<"\n";
return 0;
}
#include
using namespace std;
int n, m,dp[110][110][110];
int dfs(int i, int j, int k){//走过了i个酒馆,j个花,还有k斗酒的方案数
if(i<0 || j<0 || k<0)return 0;//遇花,遇店,酒壶里的酒都要>=0
if(i>k)return 0; //每次要喝1,所以酒馆要小于总酒量
if(j==0 && i==1 && k==1)return 1; //边界状态,一个酒馆
if(dp[i][j][k] != -1)return dp[i][j][k];
return dp[i][j][k] = (dfs(2*i,j-1,k)+dfs(i-1,j,k-1))%1000000007;
}
int main(){
memset(dp, -1, sizeof(dp));
cin>>n>>m;
cout<<dfs(2,n,m)<<"\n";
return 0;
}
总结2点:
1、首先我们注意到,一般的做题过程就是,找到某个结论(关键点,突破口),然后做优化的那种题目,比如说数据范围1e5,但是某个数据很小(发现6次就砍完,地雷范围r<10),就可以拿这个做文章,再比如一眼暴力,然后想想怎么用结论(比如说来回走动的规律,到两边的距离,双指针)这种来优化,或者说其实大多数dp类型的思维/暴力题,都有点这种意味在里面。
2、另外一个思维的切入点是,先想清楚再写代码,think twice, code once,这样不容易思路被带偏,不要上来就啪啪啪输入输出,这样后面就卡住了(起码我是这样的,会被打断,可能题意都忘记了,那还写个锤子),大体思路想好,感觉方案可行了,优化完了再写,细节具体再补充上去就行,不要上来就暴力,不是每道题都有写暴力对拍的时间成本的。 虽然在写不出来了的时候多交一个暴力骗分也是一个好习惯。
#include
using namespace std;
typedef long long LL;
struct node{
LL h, num;
bool operator <(const node &rhs)const{ return h==rhs.h ? num>rhs.num : h<rhs.h; }
};
priority_queue<node> q;
int main(){
int n; cin>>n;
LL t, ans = 0;
for(int i = 1; i <= n; i++){
cin>>t; q.push((node){t,i});
}
while(q.top().h != 1){
t = q.top().h;
n = q.top().num-1;
while(q.top().h==t&&q.top().num==n+1){//把高度相同且编号连续的竹子砍完再入堆
n++;
q.pop();
q.push((node){sqrtl(t/2+1),n});
}
ans++;
}
cout<<ans<<"\n";
return 0;
}