第十二届蓝桥杯省赛第二场C++B组真题
P3496. 特殊年份
题目:特殊年份
思路:
模拟即可
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int x;
int cnt;
bool check(int x){
int a=x%10;//个位
int b=(x/10)%10;//十位
int c=(x/100)%10;//百位
int d=x/1000;//千位
if((b==d)&&(a-c==1)) return true;
return false;
}
int main(){
while(cin>>x){
if(check(x)) cnt++;
}
printf("%d\n",cnt);
return 0;
}
P3490. 小平方
题目:小平方
思路:
模拟即可
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int n,x;
int cnt;
bool check(int x){
int cmp;
if(n%2==0) cmp=n/2;
else cmp=n/2+1;
if((x*x)%n<cmp) return true;
return false;
}
int main(){
scanf("%d",&n);
for(int i=1;i<n;i++){
if(check(i)) cnt++;
}
printf("%d\n",cnt);
return 0;
}
P3491. 完全平方数
题目:完全平方数
思路:
分解质因数即可,如果一个质因数个数是奇数就再乘一个
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
int main(){
LL x;
scanf("%lld",&x);
LL res=1;
for(int i=2;i<=x/i;i++){
if(x%i==0){
int s=0;
while(x%i==0){
x/=i;
s++;
}
if(s%2!=0) res*=i;
}
}
if(x>1) res*=x;
printf("%lld",res);
return 0;
}
P3492. 负载均衡
题目:负载均衡
思路:
时间复杂度要做到O(nlogn),对于每一个计算机,我们用一个小根堆来维护它正在执行的所有任务
对于每个任务来说,先把结束时间在起点之前的任务全部删掉,这其实就是一个找到最小值删除最小值的过程,可以用小根堆
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int N=2e5+10;
int n,m;
int s[N];//每个计算机剩余的算力
priority_queue<PII,vector<PII>,greater<PII>> q[N];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&s[i]);
while(m--){
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
while(q[b].size()&&q[b].top().x<=a){
s[b]+=q[b].top().y;
q[b].pop();
}
if(s[b]>=d){
q[b].push({a+c,d});
s[b]-=d;
printf("%d\n",s[b]);
}
else puts("-1");
}
return 0;
}
P3494. 国际象棋
题目:国际象棋
思路:
状态压缩DP,P1064 小国王+P292 炮兵阵地 的结合版
状态表示:
集合: f[i][a][b][j]表示前i列已经摆好,并且第i-1列状态是a,第i列状态是b,一共放置了j个皇后的所有方案
属性: cnt(数量)
状态计算:
不用行而用列的原因:列最多为100,如果用行,意味着状态数最多为
2
100
2^{100}
2100,但行数最多是6,那么如果用列状态数最多是
2
6
2^6
26
状态定义顺序可以随便,比如说f[i][j][a][b]也能做,只要保证用来更新的状态在当前状态之前被算出来即可
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=110,M=1<<6,K=21,mod=1e9+7;
int n,m,k;
int f[N][M][M][K];
int get_count(int x){//统计x中1的个数
int res=0;
while(x){
res++;
x-=(x&-x);
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
f[0][0][0][0]=1;//一开始棋盘上啥都没有
for(int i=1;i<=m+2;i++){//第1列到第m+2列
for(int a=0;a<1<<n;a++){
for(int b=0;b<1<<n;b++){
if(b&(a<<2)||b&(a>>2)) continue;//能相互攻击到
int t=get_count(b);
for(int c=0;c<1<<n;c++){
if(a&(c<<2)||a&(c>>2)) continue;
if(b&(c<<1)||b&(c>>1)) continue;
for(int j=t;j<=k;j++){
f[i][a][b][j]=(f[i][a][b][j]+f[i-1][c][a][j-t])%mod;
}
}
}
}
}
printf("%d\n",f[m+2][0][0][k]);//小技巧,这样就不用枚举f[m][i][j][k]了
return 0;
}
滚动数组优化:
一样的套路,可以把第一维优化到2,但会多一层循环来清空数组
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int M=1<<6,K=21,mod=1e9+7;
int n,m,k;
int f[2][M][M][K];
int get_count(int x){//统计x中1的个数
int res=0;
while(x){
res++;
x-=(x&-x);
}
return res;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
f[0][0][0][0]=1;//一开始棋盘上啥都没有
for(int i=1;i<=m+2;i++){//第1列到第m+2列
for(int a=0;a<1<<n;a++){
for(int b=0;b<1<<n;b++){
if(b&(a<<2)||b&(a>>2)) continue;//能相互攻击到
int t=get_count(b);
for(int j=t;j<=k;j++) f[i&1][a][b][j]=0;//要先清空滚动数组
for(int c=0;c<1<<n;c++){
if(a&(c<<2)||a&(c>>2)) continue;
if(b&(c<<1)||b&(c>>1)) continue;
for(int j=t;j<=k;j++){
f[i&1][a][b][j]=(f[i&1][a][b][j]+f[i-1&1][c][a][j-t])%mod;
}
}
}
}
}
printf("%d\n",f[m+2&1][0][0][k]);//小技巧,这样就不用枚举f[m][i][j][k]了
return 0;
}
差距: