第十二届蓝桥杯省赛B组部分题解
填空题
直线
#include<bits/stdc++.h>
using namespace std;
struct node{
double xx;
double yy;
node(int cinx,int ciny){
xx=cinx;
yy=ciny;
}
node(double cinx,double ciny){
xx=cinx;
yy=ciny;
}
bool operator<(const node &y) const {
if(xx==y.xx){
return yy < y.yy;
}
return xx < y.xx;
}
};
map<node,bool> mp;
vector<node> v;
int main()
{
int x,y;
cin>>x>>y;
int res=0;
for(int i=0;i<x;i++){
for(int j=0;j<y;j++){
node x1=node(i,j);
for(int p=0;p<x;p++){
for(int q=0;q<y;q++){
node y1=node(p,q);
if(x1.xx==y1.xx&&x1.yy==y1.yy) continue;
if(x1.xx!=y1.xx){
int num1=y1.yy-x1.yy;
int num2=y1.xx-x1.xx;
double k=(y1.yy-x1.yy)*1.0/(y1.xx-x1.xx);
double b=x1.yy-k*x1.xx;
if(!mp.count(node(k,b))){
mp[node(k,b)]=true;
v.push_back(node(k,b));
}
}
}
}
}
}
sort(v.begin(),v.end());
for(int i=1;i<v.size();i++){
if(fabs(v[i].yy-v[i-1].yy)>1e-8 || fabs(v[i].xx-v[i-1].xx)>1e-8)
res++;
}
cout<<res+y<<endl;
return 0;
}
//答案:40257
货物摆放(大数质数判断)
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
cin>>n;
vector<long long> ans;
for(long long i=1;i*i<=n;i++){
if(n%i==0) {
ans.push_back(i);
if((n/i)!=i) ans.push_back(n/i);
}
}
//for(int i=0;i<ans.size();i++) cout<<ans[i]<<" ";
//cout<<endl;
int res=0;
for(int i=0;i<ans.size();i++){
for(int j=0;j<ans.size();j++){
for(int k=0;k<ans.size();k++){
if(ans[i]*ans[j]*ans[k]==n) res++;
}
}
}
cout<<res<<endl;
return 0;
}
编程题
杨辉三角
//ac代码
#include<bits/stdc++.h>
using namespace std;
//因为不能二维数组不能定义太大,不然运行有问题,这里用到了剪枝,所以数组列数大胆的设置为40
int a[1000010][40];
signed main()
{
int n;
cin>>n;
if(n==1){
cout<<1<<endl;
return 0;
}
long long res=0;
a[1][0]=1;
a[1][1]=1;
for(int i=2;i<1000010;i++){
a[i][0]=1;
for(int j=1;j<=i;j++){
a[i][j]=a[i-1][j-1]+a[i-1][j];
if(a[i][j]==n){
for(int k=1;k<=i;k++) res+=k;
res+=j;
res++;
cout<<res<<endl;
return 0;
}
//进行剪枝防止超出数组范围,同时降低复杂度
//剪枝原理:int的数据存储范围差不多是1e9,与题目相符
//所以如果当前相加数字等于负数,就说明此时数字超出了int范围,后面的数据也没有求的必要
//就进行剪枝,break,这样既节省了空间也节省时间
if(a[i][j] < 0) break;
}
}
//如果在上述循环至100010的过程中,还没有找到n
//杨辉三角基本到5万行左右的数据就会大于1e9了,如果还没出现过,那么其出现的位置
//不可能在中间位置,只有可能在第n+1行,第2个数字出现
//这个规律可以在多写几行杨辉三角后总结
cout << (long long)n * (n + 1) /2 + 2 << endl;
return 0;
}
时间显示
//ac代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int dayms=86400000;
const int hms=3600000;
const int mms=60000;
const int sms=1000;
//快读
inline int read()
{
int s=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
s=s*10+ch-'0';
ch=getchar();
}
return s*f;
}
//快写
inline void write(int x)
{
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
signed main()
{
//int cintime = read();
int cintime;
cin>>cintime;
cintime%=dayms;
int t[3];
if(cintime>=hms){
t[0]=cintime/hms;
cintime%=hms;
}else t[0]=0;
if(cintime>=mms){
t[1]=cintime/mms;
cintime%=mms;
}else t[1]=0;
if(cintime>=sms){
t[2]=cintime/sms;
cintime%=sms;
}else t[2]=0;
for(int i=0;i<2;i++){
if(t[i]>=0&&t[i]<=9) printf("0%d:",t[i]);
else printf("%d:",t[i]);
}
if(t[2]>=0&&t[2]<=9) printf("0%d\n",t[2]);
else printf("%d\n",t[2]);
return 0;
}
双向排序(60分)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000;
const int maxm = 100000;
int n,m;
int a[maxn];
bool cmp(const int a,const int b){
return a>b;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++) a[i]=i;
bool issort=false;//刚开始的数组的升序的,那么如果开始的p是1,就不需要sort,节约时间
while(m--){
int p,q;
cin>>p>>q;
if(p==0) issort=true;
if(p==0&&issort==true) sort(a+1,a+q+1,cmp);
else if(p==1&&issort==true) sort(a+q,a+n+1);
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
return 0;
}
砝码称重
题意:
有n个砝码,可以放在天平两端,问有多少种可能的结果
输入样例:
3
1 4 6
输出样例:
10
样例解释:
能称出的 10 种重量是:1、2、3、4、5、6、7、9、10、11。
1 = 1;
2 = 6 − 4 (天平一边放 6,另一边放 4);
3 = 4 − 1;
4 = 4;
5 = 6 − 1;
6 = 6;
7 = 1 + 6;
9 = 4 + 6 − 1;
10 = 4 + 6;
11 = 1 + 4 + 6
解题思路:
看了很多篇题解,用dp动态背包解,dp[i][j]存储 前i个砝码能否得出j重量的结果,举例说明一下:
我们已知前0个砝码肯定能得到重量为0,所以dp[0][0]=true,那么第一个遍历的砝码我们假设w[1]=2,那么前1个砝码可以得到的重量,就有三种可能:
第一种就是0。因为前0个砝码可以为0,那么前1个砝码必然可以;即dp[1][0]=true;
第二种情况就是0+w[1]=2。这个不需要多解释,上一次重量基础上加上这次的重量;即dp[1][2]=true;
第三种情况就是|0-w[i]|=2。因为砝码可以放在天平两端,所以做减法,又因为求的是重量结果,没有负数,所以是绝对值;即dp[1][2]=true;上面的过程相当于就是在修改i=1时的dp[1][j]状态,那么我们就可以,遍历1-n个砝码,重复上述过程,依次修改状态。
那么dp状态方程,就是将上述过程反推一下
dp[i][j]= dp[i-1][j] | dp[i-1][j+w[i]] | dp[i-1][abs(j-w[i])]最后遍历dp[n]一列中有多少为true即可
//ac代码
#include<bits/stdc++.h>
using namespace std;
int w[110];
bool dp[105][1000001];//储存前i个能否得到j的重量的可行性
int main()
{
int n;
cin>>n;
int sum=0;
for(int i=1;i<=n;i++){
cin>>w[i];
sum+=w[i];//可能得到的最大的重量就是总和
}
//开始从0开始修改状态
dp[0][0]=true;//前0个砝码肯定可以得到重量0
for(int i=1;i<=n;i++){
dp[i][0]=true;
for(int j=1;j<=sum;j++){
//三种某一种成立均可
// dp[i][j]=dp[i-1][j];//第一种情况,如果前i-1砝码可以得到j,那么前i个肯定也可以
// dp[i][j]=dp[i-1][j+w[i]];//第二种情况,相加
// dp[i][j]=dp[i-1][abs(j-w[i])];//第三种情况,相减
dp[i][j]=dp[i-1][j] | dp[i-1][j+w[i]] | dp[i-1][abs(j-w[i])];
}
}
int res=0;
for(int i=1;i<=sum;i++){
if(dp[n][i] == true) {
//cout<<i<<endl;
res++;
}
}
cout<<res<<endl;
return 0;
}