文章目录
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
T1_购物单(模拟)
——题目描述——
——解——
这种题目是真的烦。
答案:5200
——Code——
#include<stdio.h>
double a[10000][2]={
180.90, 0.88,
10.25, 0.65,
56.14, 0.9,
104.65, 0.9,
100.30, 0.88,
297.15, 0.5,
26.75, 0.65,
130.62, 0.5,
240.28, 0.58,
270.62, 0.8,
115.87, 0.88,
247.34, 0.95,
73.21, 0.9,
101.00, 0.5,
79.54, 0.5,
278.44, 0.7,
199.26, 0.5,
12.97, 0.9,
166.30, 0.78,
125.50, 0.58,
84.98, 0.9,
113.35, 0.68,
166.57, 0.5,
42.56, 0.9,
81.90, 0.95,
131.78, 0.8,
255.89, 0.78,
109.17, 0.9,
146.69, 0.68,
139.33, 0.65,
141.16, 0.78,
154.74, 0.8,
59.42, 0.8,
85.44, 0.68,
293.70, 0.88,
261.79, 0.65,
11.30, 0.88,
268.27, 0.58,
128.29, 0.88,
251.03, 0.8,
208.39, 0.75,
128.88, 0.75,
62.06, 0.9,
225.87, 0.75,
12.89, 0.75,
34.28, 0.75,
62.16, 0.58,
129.12, 0.5,
218.37, 0.5,
289.69, 0.8,
};
int main()
{
double ans=0;
for(int i=0;i<10000;++i)
ans+=a[i][0]*a[i][1];
printf("%lf\n",ans);
return 0;
}
T2_等差素数列(欧拉筛暴搜)
——题目描述——
——解——
本题考察的知识点为素数筛,从用欧拉筛打出1e7以内的素数,然后枚举公差,如果没答案,适当扩大枚举范围。
答案:210
——Code——
#include<iostream>
using namespace std;
bool num[10000007];
int prime[1000006];
int Euler()
{
int cnt=0;
for(int i=2;i<=10000000;++i)
{
if(!num[i]) prime[cnt++]=i;
for(int j=0;j<cnt&&prime[j]*i<=10000000;++j)
{
num[i*prime[j]]=true;
if(!(i%prime[j])) break;
}
}
return cnt;
}
int main()
{
int len=Euler();
// for(int i=0;i<len;++i)
// cout<<prime[i]<<endl;
for(int d=1;d<=1000;++d)
{
for(int i=0;i<len-10;++i)
{
int j;
bool flag=false;
for(j=1;j<=9;++j)
if(prime[i]+j*d>=10000000||num[prime[i]+j*d])
{
flag=true;
break;
}
if(!flag) cout<<d<<" "<<prime[i]<<endl;
}
}
return 0;
}
T3_承压计算(模拟)
——题目描述——
——解——
依旧是一道模拟题,从上往下递推,设某处为第i行第j列,此处的承压
G
[
i
]
[
j
]
=
G
[
i
−
1
]
[
j
]
+
G
[
i
−
1
]
[
j
−
1
]
G[i][j]=G[i-1][j]+G[i-1][j-1]
G[i][j]=G[i−1][j]+G[i−1][j−1]
答案恰好是个整数:72665192664
——Code——
#include<iostream>
using namespace std;
double a[31][31];
int main()
{
for(int i=1;i<=29;++i)
for(int j=1;j<=i;++j)
cin>>a[i][j];
for(int i=1;i<=30;++i)
for(int j=1;j<=i;++j)
a[i][j]+=a[i-1][j]/2+a[i-1][j-1]/2;
double min30=999999,max30=-999999;
for(int i=1;i<=30;++i)
{
min30=min(a[30][i],min30);
max30=max(a[30][i],max30);
}
printf("%.0lf\n",max30*(static_cast<double>(2086458231)/min30));
return 0;
}
T4_方块分割(DFS)
——题目描述——
——解——
典型的深度优先搜索题,首先把方格坐标化,设最左下角点为
(
0
,
0
)
(0,0)
(0,0),对方格之间的线进行搜索,从
(
3
,
3
)
(3,3)
(3,3)开始,模拟中心对称图案线的性质(从起点延伸出两条中心对称的线),当线走到坐标边缘视作得出一种方案。当然,对于起点
(
3
,
3
)
(3,3)
(3,3),线有四个相同的方向可以延伸,所以会得出四个一样的方案,最终答案数需要除以4。
答案:509
——Code——
#include<iostream>
using namespace std;
int ans;
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
bool vis[7][7];
void dfs(int x,int y)
{
if(x==0||x==6||y==0||y==6)
{
++ans;
return;
}
for(int i=0;i<4;++i)
{
int X=x+dx[i];
int Y=y+dy[i];
if(X>=0&&X<=6&&Y>=0&&Y<=6&&vis[X][Y]==false)
{
vis[X][Y]=true;
vis[6-X][6-Y]=true;
dfs(X,Y);
vis[X][Y]=false;
vis[6-X][6-Y]=false;
}
}
}
int main()
{
vis[3][3]=true;
dfs(3,3);
cout<<ans/4<<endl;
}
T5_取位数(简单数学)
——题目描述——
// 求x用10进制表示时的数位长度
int len(int x){
if(x<10) return 1;
return len(x/10)+1;
}
// 取x的第k位数字
int f(int x, int k){
if(len(x)-k==0) return x%10;
return _____________________; //填空
}
int main()
{
int x = 23574;
printf("%d\n", f(x,3));
return 0;
}
——解——
可能是这10道题中写起来第二快的题,本题是典型的递归题,结合简单数学知识。当数字的长度等于k时,那么它的第k位数字就是该数的个位。如果长度大于k,那么就去掉末位,再进行比较。
答案:
f
(
x
/
10
,
k
)
f(x/10,k)
f(x/10,k)
T6_最大公共子串(动态规划)
——题目描述——
#include <stdio.h>
#include <string.h>
#define N 256
int f(const char* s1, const char* s2)
{
int a[N][N];
int len1 = strlen(s1);
int len2 = strlen(s2);
int i,j;
memset(a,0,sizeof(int)*N*N);
int max = 0;
for(i=1; i<=len1; i++){
for(j=1; j<=len2; j++){
if(s1[i-1]==s2[j-1]) {
a[i][j] = __________________________; //填空
if(a[i][j] > max) max = a[i][j];
}
}
}
return max;
}
int main()
{
printf("%d\n", f("abcdkkk", "baabcdadabc"));
return 0;
}
——解——
这10道题中做起来最快的题,前提是知道动态规划。
a
[
i
]
[
j
]
a[i][j]
a[i][j]表达的是当s1遍历到第i位且s2遍历到第j位时各往前递推,子串的长度。如果这两个位置的字符刚好相等,那么此处的值就是上一位子串长度加1,否则就是0.
答案:
a
[
i
−
1
]
[
j
−
1
]
+
1
a[i-1][j-1]+1
a[i−1][j−1]+1
T7_日期问题(???模拟)
——题目描述——
——解——
三种情况套进去都检查一下就好了。
(一开始没看到只有三种排列,代码冗余了。。。)
#include<iostream>
#include<algorithm>
using namespace std;
int num[4];
int check(int y,int m)
{
int flag=0;
if(y%400==0||y%4==0&&y%100!=0)
flag=1;
switch(m)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:return 31;
case 4:
case 6:
case 9:
case 11:return 30;
default:break;
}
return 28+flag;
}
int main()
{
char in[9];
for(int i=1;i<=8;++i)
cin>>in[i];
num[1]=(in[1]-'0')*10+in[2]-'0';
num[2]=(in[4]-'0')*10+in[5]-'0';
num[3]=(in[7]-'0')*10+in[8]-'0';
sort(num+1,num+4);
for(int i=1;i<=3;++i)
{
if(i==2) continue;
if(num[i]<60)
{
for(int j=1;j<=3;++j)
{
if(i==1&&j!=2||j==i)continue;
else
{
int k=6-i-j;
if(num[j]<=12&&num[k]<=check(num[i]+2000,num[j]))
{
cout<<num[i]+2000<<"-";
if(num[j]<10) cout<<"0"<<num[j]<<"-";
else cout<<num[j]<<"-";
if(num[k]<10) cout<<"0"<<num[k]<<endl;
else cout<<num[k]<<endl;
}
}
}
}
else
{
for(int j=1;j<=3;++j)
{
if(j==i) continue;
else
{
int k=6-i-j;
if(num[j]<=12&&num[k]<=check(num[i]+1900,num[j]))
{
cout<<num[i]+1900<<"-";
if(num[j]<10) cout<<"0"<<num[j]<<"-";
else cout<<num[j]<<"-";
if(num[k]<10) cout<<"0"<<num[k]<<endl;
else cout<<num[k]<<endl;
}
}
}
}
}
return 0;
}
T8_包子凑数(数论)
——题目描述——
——解——
本题是一道数论题
先看无限多个的情况,比如样例4,6只能凑出偶数,在比如3,12,48只能凑出3的倍数,通过不完全归纳,可以得出结论:只有当所有数字的最大公约数不为1,凑不出的情况为有限个。
当确定答案为有限个时,接下来要做的就是粗略确定答案的上限。Ai最大为100,两个最大且互质的数为99和100,那么9900以后的整数一定都能被这两个数表示,证明过程可以参考我之前博客中的T4
现在可以延伸一下这个结论,对于任意两个互质的正整数a和b,大于等于ab的数都能被表示为ax+by,其中x和y均为正整数。
为了不浪费时间去找数组A中乘积最小的一对数字,可直接采用9900作为上限。
然后,用筛子把能访问到的数筛掉,顺便统计答案。
——Code——
#include<iostream>
using namespace std;
int n;
int a[101];
bool vis[9901];
int gcd(int a,int b)
{
int r;
do
{
r=a%b;
a=b;
b=r;
}while(r!=0);
return a;
}
int search()
{
int ans=0;
for(int i=1;i<=9900;++i)
{
if(!vis[i])
{
++ans;
continue;
}
for(int j=1;j<=n;++j)
vis[i+a[j]]=true;
}
return ans;
}
int main()
{
cin>>n;
bool flag=true;
int r;
for(int i=1;i<=n;++i)
{
cin>>a[i];
vis[a[i]]=true;
if(flag)
{
r=a[i];
flag=false;
}
r=gcd(a[i],r);
}
if(r!=1) cout<<"INF\n"<<endl;
else cout<<search()<<endl;
return 0;
}
T9_分巧克力(二分)
——题目描述——
——解——
本题是一道典型的二分题,二分区间的可行域为左侧,区间的下限为1,上限为所有巧克力中的最长边。
检查枚举的边长是否符合要求也比较简单,只要把所有巧克力能裁剪出的数量累加即可。
——Code——
#include<iostream>
#include<algorithm>
using namespace std;
int n,k;
int a[2][100005];
bool check(int len)
{
int cnt=0;
for(int i=1;i<=n;++i)
cnt+=(a[0][i]/len)*(a[1][i]/len);
if(cnt>=k) return true;
return false;
}
int main()
{
cin>>n>>k;
int maxl=-1;
for(int i=1;i<=n;++i)
{
cin>>a[0][i]>>a[1][i];
maxl=max(maxl,max(a[0][i],a[1][i]));
}
int left=1,right=maxl;
int ans=0;
while(left<=right)
{
int mid=(left+right)/2;
if(check(mid))
{
left=mid+1;
ans=mid;
}
else right=mid-1;
}
cout<<ans<<endl;
return 0;
}
T10_K倍数列(前缀和)
——题目描述——
——解——
还是比较水的一题,主要考察前缀和。
在读入数据时存储从该数据开始以及之前所有数据的和,并且对
k
k
k取模。并对取模的结果进行统计,如果为0,则答案数直接加1。在没有取模之前,
i
<
j
i<j
i<j时,必定有
s
u
m
[
i
]
<
s
u
m
[
j
]
sum[i]<sum[j]
sum[i]<sum[j],而
i
到
j
i到j
i到j这一段区间的和即为
s
u
m
[
j
]
−
s
u
m
[
i
]
sum[j]-sum[i]
sum[j]−sum[i],所以取模后,如果存在两个不等的下标
i
和
j
i和j
i和j且
s
u
m
[
j
]
−
s
u
m
[
i
]
=
0
sum[j]-sum[i]=0
sum[j]−sum[i]=0,那么从
i
到
j
i到j
i到j的和是
k
k
k的倍数,因此任意两个相等的
s
u
m
sum
sum之间能产生一个答案。累计
0
到
k
−
1
0到k-1
0到k−1每个数出现的此时,分别套用组合数公式,累加起来。最后加上之前统计的0的个数,记为最终答案。
——Code——
#include<iostream>
#include<cstring>
using namespace std;
int sum[100005];
int cnt[100005];
int n,k;
int main()
{
long long ans=0;
cin>>n>>k;
memset(cnt,-1,sizeof(cnt));
for(int i=1;i<=n;++i)
{
int num;
cin>>num;
sum[i]=(num%k+sum[i-1])%k;
++cnt[sum[i]];
ans+=cnt[sum[i]];
if(!sum[i]) ++ans;
}
cout<<ans<<endl;
return 0;
}
把开头的话再重复一下:
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
编程题代码仅供参考,没跑过原题数据。
上一篇题解也是这样的(学校的锅…)