A
答案:624
思路:枚举
代码:
#include <bits/stdc++.h>
using namespace std;
int check(int x){
int cnt = 0;
while(x > 0){
int p =x %10;
x/=10;
if(p == 2)
cnt++;
}
return cnt;
}
int main()
{
int ans = 0;
for(int i = 1; i <= 2020 ;++i){
ans += check(i);
}
cout<<ans<<endl;
return 0;
}
B
答案:2481215
思路:枚举
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int gcd(int a,int b){
if(b == 0) return a;
return gcd(b,a % b);
}
int main()
{
ll ans = 0;
// cout<<gcd(15,20);
for(int i = 1;i <= 2020; ++i){
for(int j = 1;j <= 2020 ;++j){
if(gcd(i,j) == 1)
ans++;
}
}
cout<<ans<<endl;
return 0;
}
C
答案:761
思路:找规律,第i行i列依次为1,5,13,25,41,第 i i i个数与 i − 1 i-1 i−1个数的差为 ( i − 1 ) × 4 (i-1)\times4 (i−1)×4
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
int ans = 1;
for(int i = 2;i <= 20; ++i){
ans += 4 * (i - 1);
}
cout<<ans;
return 0;
}
D
答案:8879
思路:
首先启动计算器,先看一下间隔时间,加一天共计7580天。
跑步公里就是总天数加上周一的天数,加上每个月1号不是周一的天数。
容易发现,设某天与第一天间隔x天,若x%7 == 2,说明这天为星期一。就可以O(1)的判断某天是否为周一。
枚举每个月的1号,算出是开始后的第几天,再判断这天是否为周一。
同时计算任意两个日期的总天数还可以用上面计算器算的天数验证结果是否正确。
补充:
蓝桥杯经常有年份相关的,闰年的计算方式是:
1.普通年份能被4整除,且不能被100整除的,是闰年。(如2004年就是闰年)
2.世纪年份能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int day[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
struct da
{
int y,m,d;
da() {}
da(int a,int b,int c): y(a),m(b),d(c){}
};
int check(int y)//判断闰年
{
if((y % 100 == 0) && (y % 400 == 0))
return 1;
if((y % 100 != 0) && (y % 4 == 0))
return 1;
return 0;
}
int cal(da s,da e)//两个日期的天数
{
int d = 0;
//首年
if(s.y != e.y){
for(int i = s.m ;i <= 12; ++i){
if(check(s.y))
{
if(i == 2){
if(i == s.m )
d += 29 - s.d + 1;
else d += 29;
}
else{
if(i == s.m )
d += day[i - 1] - s.d + 1;
else d += day[i - 1];
}
}
else{
if(i == s.m )
d += day[i - 1] - s.d + 1;
else d += day[i - 1];
}
}
}
// cout<<d<<endl;
for(int i = s.y + 1 ;i < e.y; ++i){
if(check(i))
d += 366;
else d += 365;
}
// cout<<d<<endl;
for(int i = 1; i <= e.m ; ++i){
if(check(e.y) )
{
if(i == 2){
if(i == e.m )
d += e.d;
else d += 29;
}
else{
if(i == e.m )
d += e.d;
else d += day[i - 1];
}
}
else{
if(i == e.m )
d += e.d;
else d += day[i - 1];
}
}
return d;
}
int main()
{
da s(2000,1,1),e(2020,10,1);
int ans =cal(s,e);
// cout<<ans<<endl;
int cnt = ans;
for(int i = 1;i <= cnt; ++i){
if( (i-1) % 7 == 2)
ans++;
}
// cout<<ans<<endl;
for(int i = s.y; i <= e.y; i++){
for(int j = 1;j <= 12; j++){
if(i == e.y && j > e.m)
break;
da u(i,j,1);
cnt = cal(s,u);
if((cnt - 1) % 7 != 2){
// cout<<u.y<<" "<<u.m<<" "<<u.d<<endl;
ans++;
}
}
}
cout<<ans<<endl;
return 0;
}
E
答案:80
思路:搜索+并查集
对于每个灯有选或不选两种状态,一共是
2
7
2^7
27状态,对于每个状态判断当前选的是否连通。
如果选的正好有一个连通块,答案加一。
对于每个状态,用并查集进行两两连通,数有几个连通块即可。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int pre[8];
int a[8][8];
int vis[8],ans =0;
// abcdefg
// 1234567
void init(){
a[1][6] = a[1][2] = 1;
a[2][1] = a[2][7] = a[2][3] = 1;
a[3][4] = a[3][7] = a[3][2] = 1;
a[4][3] = a[4][5] = 1;
a[5][4] = a[5][7] = a[5][6] = 1;
a[6][1] = a[6][7] = a[6][5] = 1;
a[7][6] = a[7][2] = a[7][3] = a[7][5] = 1;
}
int find(int x){
if(pre[x] == x )
return x ;
else return pre[x] = find(pre[x]);
}
void dfs(int pos)
{
if(pos > 7){
for(int i = 1;i <= 7; i++)
pre[i] = i;
for(int i = 1;i <= 7; i++){
for(int j = 1;j <= 7; j++){
if(a[i][j] && vis[i] && vis[j]){
int fa = find(i),fb = find(j);
// cout<< fa<<" "<<fb<<endl;
if(fa != fb)
pre[fa] = fb;
}
}
}
int cnt = 0;
for(int i = 1;i <= 7;++i){
if(vis[i] && (pre[i] == i))
cnt++;
}
if(cnt == 1)
ans++;
return;
}
vis[pos] = 1;
dfs(pos + 1);
vis[pos] = 0;
dfs(pos + 1);
}
int main()
{
init();
dfs(1);
cout<<ans<<endl;
return 0;
}
F 成绩统计
题目链接:https://www.acwing.com/problem/content/2874/
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int a[maxn];
int main()
{
int n,cnt1 = 0,cnt2 = 0;
cin>>n;
for(int i = 1;i <= n; ++i){
cin>>a[i];
if(a[i] >= 60) cnt1++;
if(a[i] >= 85) cnt2++;
}
int a = cnt1 * 1.0 / n * 1000;
int b = cnt2 * 1.0 / n * 1000;
// cout<<a<<" "<<b<<endl;
if(a % 10>= 5)
cout<<a / 10+ 1<<"%"<<endl;
else
cout<<a / 10 <<"%"<<endl;
if(b % 10 >= 5)
cout<<b / 10 + 1<<"%"<<endl;
else
cout<<b / 10<<"%"<<endl;
return 0;
}
或者直接用四舍五入函数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int a[maxn];
int main()
{
int n,cnt1 = 0,cnt2 = 0;
cin>>n;
for(int i = 1;i <= n; ++i){
cin>>a[i];
if(a[i] >= 60) cnt1++;
if(a[i] >= 85) cnt2++;
}
double a = cnt1 * 1.0 / n * 100;
double b = cnt2 * 1.0 / n * 100;
cout<<round(a)<<"%"<<endl;
cout<<round(b)<<"%"<<endl;
return 0;
}
补充:
c++中的一些函数:
floor : 不大于自变量的最大整数
ceil: 不小于自变量的最大整数
round:四舍五入到最邻近的整数
G
链接:https://www.acwing.com/problem/content/2870/
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
int mo[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
int n[4];
int run(int y){
if(y % 100 == 0 && y % 400 == 0)
return 1;
if(y % 100 != 0 && y % 4 == 0)
return 0;
return 1;
}
string change(int x)
{
string s="";
while(x > 0){
int p =x % 10;
s += (p +'0');
x /= 10;
}
reverse(s.begin(),s.end());
return s;
}
int main()
{
// int s;
string s,ans1 = "",ans2 = "";
cin>>s;
int m = (s[4] - '0') * 10 + s[5] - '0';
int d = (s[6] - '0') * 10 + s[7] - '0';
int y = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + s[3] - '0';
int yy,mm,dd;
for(int i = y; ; i++){
string s1 = "",s2 = "";
mo[1] = 28;
s1 = change(i);
mm = (s1[3] - '0') * 10 + s1[2] - '0';
dd = (s1[1] - '0') * 10 + s1[0] - '0';
if(run(i)) mo[1] = 29;
// cout<<i<<endl;
// cout<<mm<<" "<<dd<<endl;
if(mm > 12 || mm <= 0 || dd > mo[mm - 1] || dd <= 0 )
continue;
if(y == i && ( mm < m || (mm == m && dd <= d)))
continue;
s2 += s1;
reverse(s1.begin(),s1.end());
s2 += s1;
if(s2[0] == s2[2] && s2[1] == s2[3] && s2[0] != s2[1]){
ans2 += s2;
if(ans1 == "") ans1 += s2;
cout<<ans1<<endl;
cout<<ans2<<endl;
break;
}
else{
if(ans1 == "") ans1 += s2;
}
}
return 0;
}
H
链接:https://www.acwing.com/problem/content/2875/
思路:
暴力:
对于这个题场上可以考虑暴力骗分大法,枚举所有区间,然后在暴力的基础上用前缀和优化,预处理每一位的字母出现次数前缀。这样每个区间每个字母的个数可以O(1)查询。
然后遍历所有区间,时间复杂度是 O ( n 2 ) O(n^2) O(n2),能拿到一半的分。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
int l[maxn][25];
int main()
{
string s;
int ans = 0,cnt = 0;
cin>>s;
for(int i = 0;i <s.length(); ++i){
if(i != 0)
for (int j = 0; j < 25; j++)
l[i][j] = l[i - 1][j];
l[i][s[i] - 'a']++;
}
for(int i = 0;i < s.length(); i++){
for (int j = i ;j <s.length(); ++j){
cnt = 0;
for(int k = 0;k < 25 ;k++){
if(l[j][k] == 0)
continue;
if(i == 0)
cnt++;
else if(l[j][k] - l[i - 1][k] > 0)
cnt++;
}
ans += cnt;
}
}
cout<<ans<<endl;
return 0;
}
正解: dp,时间复杂度O(n)
d
p
[
i
]
dp[i]
dp[i] 表示以第i位为结尾的串的权值和
容易发现如果这一位字母从未出现过,那么以第i位为结尾的串每个串都会出现新的字母,每个串都要加1,就是 d p [ i ] = d p [ i − 1 ] + i + 1 ; dp[i] = dp[i - 1] + i +1; dp[i]=dp[i−1]+i+1;
如果这一位字母出现过,记上一次出现的位置为last,包含last的以第i位为结尾的串每个串不变,不包含的每一个串要加一,也就是 d p [ i ] = d p [ i − 1 ] + i − l a s t dp[i] = dp[i - 1] + i - last dp[i]=dp[i−1]+i−last
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
map<char,int> last;
int dp[maxn];
int main()
{
string s;
ll ans = 0;
cin>>s;
dp[0] = 1;
last[s[0]] = 0;
for(int i = 1;i < s.length(); i++){
if(last.find(s[i]) == last.end()){
dp[i] = dp[i - 1] + i +1;
last[s[i]] = i;
}
else{
dp[i] = dp[i - 1] + i - last[s[i]];
last[s[i]] = i;
}
// cout<<dp[i]<<" ";
}
// cout<<endl;
for(int i = 0;i < s.length(); ++i)
ans += dp[i]* 1ll;
cout<<ans<<endl;
return 0;
}
I
链接:https://www.acwing.com/problem/content/2876/
思路:
一半的数据这么小,骗分骗分,不骗不是人,枚举小于3的情况,可以骗30%的分。
#include <bits/stdc++.h>
using namespace std;
#define PII pair<double,double>
typedef long long ll;
const int maxn = 1e6+5;
int a[maxn],b[maxn];
PII po[maxn];
int n;
PII cal(int i,int j)
{
double x1,y1;
x1 = (b[j] - b[i]) * 1.0 / (a[i] - a[j]);
y1 = a[i] * 1.0 * x1 + b[i];
return {x1,y1};
}
int main()
{
int ans,f = 0;
cin>>n;
for(int i = 1;i <= n; ++i)
cin>>a[i]>>b[i];
for(int i = 1;i <= n; ++i)
if(a[i] != a[1] || b[i] != b[1]){
f = 1;break;
}
if(n == 1|| f == 0) ans = 2;
f = 0;
for(int i = 1;i <= n; ++i)
if(a[i] != a[1]){
f = 1;break;
}
if(f == 0)
ans = n + 1;
else{
if(n == 2){
if(a[1] != a[2]) ans = 4;
else
if(b[1] != b[2]) ans = 3;
}
if(n == 3){
int cnt = 0;
f =1;
for(int i = 1;i <= n; i++){
for(int j = i + 1;j <= n;++j ){
po[++cnt] = cal(i,j);
if(po[cnt] != po[1])
f = 0;
}
}
if(f)
ans =6;
else
ans =7;
}
}
cout<<ans<<endl;
return 0;
}