第一题、门牌制作
#include<stdio.h>
int main(){
int cnt=0;
for(int i=1;i<=2020;i++){
for(int j=i;j>0;j=j/10){
if(j%10==2){
cnt++;
}
}
}
//例如2000->0
//200->0
//20->0
//2->2--->cnt ++
printf("%d",cnt);
return 0;
}
答案:624
第二题、既约分数
#include<stdio.h>
int gcd(int a,int b){
int ret = 0;
int cnt = 0;
if(a%b==0)
ret = b;
else
ret = gcd(b,a%b);
}//求最大公约数
int main(){
double a=0,b=0;
int cnt = 0;
for(a=1;a<=2020;a++){
for(b=1;b<=2020;b++){
if(gcd(a,b)==1){
cnt ++;
}
}
}
printf("%d",cnt);
return 0;
}
答案:2481215
第三题、蛇形填数
(1,1):1 + (1-1)^4 = 1
(2,2):1 + (2-1)^4 = 5
(3,3):5 + (3-1)^4 = 13
(4,4):13 + (4-1)^4 = 25
(5,5):25+ (5-1)^4 = 41
得出结论:(n-1)^2+n^2=(n,n)的结果,即20^2+19^2=761
答案:761
第四题、跑步锻炼
首先设一个月份的数组,用来记录每个月的天数,然后考虑闰年和平年对二月天数的影响。
因为题目问的是多少千米,那么普通天数就相当于1千米,总和公式为:
2000.1.1~2020.10.1总天数 + 2000.1.1~2020.10.1中是月初但不是周一的天+2000.1.1~2020.10.1中周一的天数
是月初但不是周一的天数要设一个判断条件if((截至目前的总天数 + 6) % 7 != 1)
{因为他说了2000.1.1是周六,就相当于原数从Sun开始整体向右移了六个单位,这样是不是更好理解了}
比如说2000.1的日历
将1月补齐需要整除7减2加6,因此(sum - 2 + 6) / 7就是这么来的
#include<stdio.h>
int main(){
int sum = 0, s = 0;
int month[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
for(int i = 2000; i < 2020; i++)
{
if(i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
{
month[2]++; //闰年的话二月加一
}
for(int i = 1; i <= 12;i++)
{
if((sum + 6) % 7 != 1)
{
s++; //计算是月初且不是周一的日子
}
sum += month[i];
}
if(month[2] == 29)
{
month[2]--;
} //避免闰年的二月重复加一
}
month[2]++;
//2020年的前9个月
for(int i = 1; i <= 9; i++)
{
if((sum + 6) % 7 != 1)
{
s++; //计算是月初且不是周一的日子
}
sum += month[i];
}
//加上2020.10.1日
sum += 1;
s++;
int z = sum + s + (sum - 2 + 6) / 7;
printf("%d",z);
return 0;
}
答案:8879
第五题、七段码
#include<stdio.h>
int ans;
int e[10][10],p[10],use[10];
void init() //连边建图
{
e[1][2]=e[1][6]=1;
e[2][1]=e[2][7]=e[2][3]=1;
e[3][2]=e[3][4]=e[3][7]=1;
e[4][3]=e[4][5]=1;
e[5][4]=e[5][6]=e[5][7]=1;
e[6][1]=e[6][5]=e[6][7]=1;
}
int find(int x){ //并查集
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void dfs(int d){
if(d==8)
{
for(int i=1;i<=7;i++) //初始化
p[i]=i;
for(int i=1;i<=7;i++)
for(int j=1;j<=7;j++)
if(e[i][j]&&use[i]&&use[j])
p[find(i)]=find(j); //用并查集把相邻的亮边存放到一个P集合里,根节点为第一个边的序号
int k=0;
for(int i=1;i<=7;i++)
if(use[i] && p[i]==i)
k++;
if(k==1) //所有亮边都在同一个集合中
ans++;
return;
}
use[d]=1; //打开d这个灯,继续开关下一个灯
dfs(d+1);
use[d]=0; //关闭d这个灯,继续开关下一个灯
dfs(d+1);
}
int main()
{
init();
dfs(1);
printf("%d",ans);
}
答案:80
第六题:成绩统计
#include<stdio.h>
int main(){
int n,s;//用n表示总人数,s表示学生的分数
int a=0,b=0;//a代表合格人数,b代表优秀的人数
float p,e;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&s);
if(s>=60){
a++;
}
if(s>=85){
b++;
}
}
p=(float)a/n*100;
e=(float)b/n*100;
int P=(int)(p+0.5);//P代表及格率,E代表优秀率
int E=(int)(e+0.5);//四舍五入变成整数百分比
printf("%d%%\n%d%%",P,E);//两个%%才能得到XX%
return 0;
}
第七题 :回文日期
#include<stdio.h>
int F(int x){
int t;
if(x%400==0||x%4==0&&x%100!=0)
t = 1;
else
t = 0;
return t;
} //判断是否为闰年 ,防止输入不合法日期
int main(){
int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int x;
scanf("%d",&x);
int y=x/10000;//输入的年
int m=x%10000/100;//输入的月
int d=x%100;//输入的日
int flag=0;
int c=y%10*10+y%100/10;//年对应的回文月
int b=y/100%10*10+y/1000;//年对应的回文日
if(F(y))
a[1]=29;
else
a[1]=28;
if((c>m&&c<13)||(c==m&&b>d&&b<=a[c-1])){//当年对应的回文日期在输入的日期之后
flag=1;
}
if((y/1000!=y%10)&&(y%100==c%10*10+c/10)&&(c==b)){//判断当年对应的回文日期是否是ABABBABA型日期
flag=0;
}
while(y<=8999){
y++;
m=y%10*10+y%100/10;//年份回文月
d=y/100%10*10+y/1000;//年份回文日
if(m>12||d>31)
continue;
if((flag!=1)&&m>0&&m<13&&d>0&&d<=a[m-1]){//找回文型
if(m<10){
printf("%d0%d%d\n",y,m,d);
}else if(d<10){
printf("%d%d0%d\n",y,m,d);
}else{
printf("%d%d%d\n",y,m,d);
}
flag=1;
}
if((y/1000!=y%10)&&(y%100==m%10*10+m/10)&&(m==d)){
if(m<10){
printf("%d0%d%d\n",y,m,d);
}else if(d<10){
printf("%d%d0%d\n",y,m,d);
}else{
printf("%d%d%d\n",y,m,d);
}
break;
}
}
return 0;
}
第八题:子串分值和
#include<iostream>//使用动态规划比较好理解
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=2e5+10;
ll ans;//总个数->定义为long long ,否则会爆
int id[30][maxn];//每个字母的id 对应的位置
int cnt[30];//字母id 对应的数量
char a[maxn];//定义字符数组
int b[30];//各个字符区间段位置
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>a+1; //记得加1
int len=strlen(a+1);
// cout<<len<<endl;
for(int i=1;i<=len;i++)
{
id[a[i]-'a'][++cnt[a[i]-'a']]=i;//字母出现的最后位置
}
for(int i=1;i<=len;i++)
{
int front=0;//统计不同字符数
for(int j=0;j<26;j++)//26个字母跑一遍
{
if(id[j][cnt[j]]>=i)//这个字母在i后面
{
int t=lower_bound(id[j],id[j]+1+cnt[j],i)-id[j];//就是二分查找
b[++front] =id[j][t];//不同字符出现的第一个位置
}
}
sort(b+1,b+1+front);//对i后面出现的字母排一下序
int last=i;//当前正在索引的位置
for(int j=2;j<=front;j++)//跑一遍下一个位置 ->其实这里就是第几个不同字符
{
ans+=(b[j]-last)*(j-1);
//b[j]-last是该位字母去上一个字母=距离差 ->其实就是有几个重复的这样的块
//然后再 * 这个块的长度,当前字符位置-1,其实就是对前面的做处理
//只是需要当前这个字符做标志,j-1是除去当前字符,然后将(b[j]-last)个段 *(前面不同字符个数j-1);
last=b[j];//将索引位置更新
}
ans+=(len-last+1)*front; //最后的位置,就是最长的一个段;
}
cout<<ans<<endl;
return 0;
}
第九题:平面切分
#include<bits/stdc++.h>
using namespace std;
long double s[1010][2];//存储直线的A,B
long long ans;
bool st[1010]; //false表示不是重边
pair<long double,long double> p;
int main(){
int n;
cin>>n;
for(int i=0;i<n;i++){
cin>>s[i][0]>>s[i][1];
set<pair<long double,long double> > points;
for(int j=0;j<i;j++){
if(st[j])continue;//直线是重边,跳过
if(s[i][0]==s[j][0]){//两条直线斜率相等时,判断是平行还是重合
if(s[i][1]==s[j][1]){
st[i]=true;//待添加直线是重边,退出循环
break;
}else continue;//直线平行,不需要计算交点
}
p.first=(s[j][1]-s[i][1])/(s[i][0]-s[j][0]);//交点的x坐标
p.second=s[i][0]*p.first+s[i][1];//交点的y坐标
points.insert(p);
}
if(!st[i])ans+=points.size()+1;//若当前直线不是重边,更新答案
}
cout<<ans+1;
return 0;
}
第十题:字串排序
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 135, M = 10010;
int f[N][30][N];//chcnt[i][j]记录第i个位置取字母j+'a'的逆序对最大值
int chcnt[N][30];//mlen[i]记录每个位置的最大值
int mlen[N];
void dp()
{
for (int i = 2; i < N; ++i)
{
int m = 0;
for (int j = 1; j <= 'z' - 'a'; ++j)
{
for (int k = 1; k < i; ++k)
{
if (k > 1) f[i][j][k] = f[i - 1][j][k - 1] + i - k;
else f[i][j][k] = chcnt[i - 1][j - 1] + i - 1;
chcnt[i][j] = max(chcnt[i][j], f[i][j][k]);
}
m = max(m, chcnt[i][j]);
}
mlen[i] = m;
}
}
int main()
{
dp();
int score = 0;
cin >> score;//找出最短长度值
int beg = 0;
for (int i = 1; i < N; ++i)
if (mlen[i] >= score)
{
beg = i;
break;
}
int curr = 0; //用于记录逆序值
int same = 1; //记录后缀中有多少个相同字母
char last = 'z' + 1;//记录上一个字母是什么
for (int i = beg; i > 0; --i)
{ //从a开始枚举
int j = 0;
for (; j <= last - 'a'; ++j)
{
if (j == last - 'a') curr -= same;
if (curr + chcnt[i][j] >= score)
{
curr += i - 1;
break;
}
}
if (j == last - 'a') same++;
else
{
last = j + 'a';
same = 1;
}
cout << last;
}
cout << endl;
return 0;
}