入门阶段
Part 1 入门阶段
Part 1.1 从零开始
P1421 小玉买文具
基础语法,可以考虑扩大十倍用a*10+b / 19 来避免取整。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int main(){
int a, b;
cin >> a >> b;
cout << (a * 10 + b) / 19;
system("pause");
return 0;
}
P1909 买铅笔
8说了,自己看吧
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int n;
int x, y, ans = INF;
int main(){
cin >> n;
for(int i = 1 ; i <= 3 ; ++ i){
cin >> x >> y;
ans = min(ans, ((n - 1) / x + 1) * y);
}
cout << ans;
system("pause");
return 0;
}
P1089 津津的储蓄计划
8说了,自己看吧
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int a[13];
int main(){
int ans = 0, mom = 0;
for(int i = 1 ; i <= 12 ; ++ i){
cin >> a[i];
ans += 300;
if(ans < a[i]){
cout << "-" << i;
// system("pause");
return 0;
}
ans -= a[i];
mom += ans / 100 * 100;
ans %= 100;
}
cout << ans + mom * 1.2;
system("pause");
return 0;
}
P1085 不高兴的津津
8说了,自己看吧
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int a, b, mx = -1, ans = 0;
int main(){
for(int i = 1 ; i <= 7 ; ++ i){
cin >> a >> b;
if(a+b > 8 && a+b > mx){
mx = a + b;
ans = i;
}
}
printf("%d", ans);
system("pause");
return 0;
}
P1035 级数求和
8说了,自己看吧
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int main(){
double ans = 0;
int k;
cin >> k;
for(int i = 1 ; ; ++ i){
ans += 1.0 / i;
if(ans > k){
cout << i << endl;
break;
}
}
system("pause");
return 0;
}
P1980 计数问题
这题还是有点意思。 考虑最简单的思路,遍历然后计算每位的贡献,但是复杂度是nlog10(n)
但是还可以有log10(n)的写法 考虑计算每一位对所有答案的贡献。 比如1-10846为例,计算含目标数字不为0的情况,共有三种情况。
计算1-10846十位为7的个数: 此时a = 108 b=4 c=6 ,不难看出其实是将原数拆成了a,b,c三个部分 那么贡献=108 * 10 因为左边a从0~107与b=7再和c从0~9组合构成所有答案
计算1-10846十位为4的个数: 那么贡献=108 * 10 + 6 + 1 因为左边a从0~107与b=4再和c从0~9组合 + 左边a=108 b=4 c=0~6构成所有答案
计算1-10846十位为3的个数: 那么贡献=109 * 10 因为左边a从0~108与b=3再和c从0~9组合构成所有答案
最后还要注意如果要计算的是0,情况还有所不同需要特殊判断。 计算1-10846千位为0的个数 那么贡献=(1-1) * 1000 + 846 + 1 因为a从1~1 b=0 c从0~846组合构成所有答案
计算1-10846十位为0的个数 那么贡献=108 * 1000 因为a从1~108 b=0 c从0~9组合构成所有答案
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int main(){
int n, x;
cin >> n >> x;
int t = 1, ans = 0;
while(t <= n){
int a = n / (t * 10);
int b = n / t % 10;
int c = n % t;
if(x){
if(b < x) ans += a * t;
if(b == x) ans += a * t + c + 1;
if(b > x) ans += (a + 1) * t;
}
else{
if(b) ans += a * t;
else ans += (a - 1) * t + c + 1;
}
t *= 10;
}
cout << ans << endl;
system("pause");
return 0;
}
P1014 Cantor表
不讨喜的规律题
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
ll n;
int main(){
cin >> n;
ll i = 1;
while(i * (i + 1) / 2 < n) i ++;
ll j = n - i * (i - 1) / 2;
if(i&1) cout << i - j + 1 << '/' << 1 + j - 1;
else cout << 1 + j - 1 << '/' << i - j + 1;
system("pause");
return 0;
}
P1307 数字反转
8说了,自己看
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
char s[15];
int main(){
scanf("%s", s + 1);
int ln = strlen(s + 1);
int i = 1, j = ln, ans = 0;
if(s[i] == '-') i ++;
while(j >= i) ans = ans * 10 + s[j] - '0', j --;
if(i>1) cout << "-";
cout << ans;
system("pause");
return 0;
}
Part 1.2 数组基础
P1046 陶陶摘苹果
8说了,自己看吧
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int x[11], ans;
int main(){
for(int i = 1 ; i <= 10 ; ++ i){
cin >> x[i];
x[i] -= 30;
}
cin >> x[0];
for(int i = 1 ; i <= 10 ; ++ i){
if(x[i] <= x[0]) ans ++;
}
cout << ans;
system("pause");
return 0;
}
P1047 校门外的树
暂时想到的三种解法
第一种,每个区间类似于染色标记,最后遍历一遍看哪些未被染色。复杂度O(m*l)
第二种,每个区间排序后合并,时间复杂度为O(mlogm)
第三种,写起来最方便,也是本题解的做法。考虑差分思想,每个起点+1,终点后面一个位置-1。最后遍历看0的数量。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int n, m, x, y, ans;
int a[maxn];
int main(){
cin >> n >> m;
for(int i = 1 ; i <= m ; ++ i){
cin >> x >> y;
a[x] += 1;
a[y + 1] -= 1;
}
for(int i = 0 ; i <= n ; ++ i){
if(i) a[i] = a[i-1] + a[i];
if(a[i] == 0) ans ++;
}
cout << ans;
system("pause");
return 0;
}
P1427 小鱼的数字游戏
基础的栈思想
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int x;
stack<int> s;
int main(){
while(scanf("%d", &x) && x){
s.push(x);
}
while(s.size()){
printf("%d%c", s.top(), s.size()>1?' ':'\n');
s.pop();
}
system("pause");
return 0;
}
P2141 珠心算测验
注意读题,2+3=5和1+4=5只算一种
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e4 + 10;
int n, x[102], len, vis[maxn], ans = 0;
int main(){
cin >> n;
for(int i = 1 ; i <= n ; ++ i){
cin >> x[i];
vis[x[i]] ++;
}
sort(x + 1, x + 1 + n);
len = unique(x + 1, x + 1 + n) - x - 1;
for(int i = 3 ; i <= len ; ++ i){
for(int j = 1 ; j < i ; ++ j){
if(vis[x[i]-x[j]] && x[i]-x[j] < x[j]){
ans ++;
break;
}
}
}
cout << ans;
system("pause");
return 0;
}
P5594 【XR-4】模拟赛
8说了
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e3 + 10;
int n, m, k;
int a[maxn][maxn], x;
int main(){
cin >> n >> m >> k;
for(int i = 1 ; i <= n ; ++ i){
int p = 0;
for(int j = 1 ; j <= m ; ++ j){
cin >> x;
a[x][++p] = 1;
}
}
for(int i = 1 ; i <= k ; ++ i){
int t = 0;
for(int j = 1 ; j <= m ; ++ j) t += a[i][j];
printf("%d%c", t, i!=k?' ':'\n');
}
system("pause");
return 0;
}
Part 1.3 字符串基础
P5015 标题统计
8说了
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e3 + 10;
string s;
int main(){
getline(cin, s);
int ans = 0;
for(int i = 0 ; i < s.length() ; ++ i){
if((s[i] <= 'z' && s[i] >= 'a') || (s[i] >= '0' && s[i] <= '9') || (s[i] >= 'A' && s[i] <= 'Z')){
ans ++;
}
}
cout << ans;
system("pause");
return 0;
}
P1055 ISBN号码
8说了
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e3 + 10;
string s;
int main(){
cin >> s;
int ln = s.length();
int x = (s[0]-'0')*1 + (s[2]-'0')*2 + (s[3]-'0')*3 + (s[4]-'0')*4 + (s[6]-'0')*5
+ (s[7]-'0')*6 + (s[8]-'0')*7 + (s[9]-'0')*8 + (s[10]-'0')*9;
x %= 11;
if(x == 10){
if(s[12] == 'X') cout << "Right";
else{
cout << s.substr(0, 12) << 'X';
}
}
else{
if(s[12] == x + '0') cout << "Right";
else{
cout << s.substr(0, 12) << x;
}
}
system("pause");
return 0;
}
P1308 统计单词数
8说了
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e3 + 10;
string s, t;
int pos = -1, cnt;
int main(){
cin >> s;
getchar();
getline(cin, t);
int ls = s.length();
for(int i = 0 ; i < ls ; ++ i) if(s[i] <= 'Z' && s[i] >= 'A') s[i] = s[i] - 'A' + 'a';
int lt = t.length();
for(int i = 0 ; i < lt ; ++ i) if(t[i] <= 'Z' && t[i] >= 'A') t[i] = t[i] - 'A' + 'a';
for(int i = 0 ; i < lt - ls ; ++ i){
// cout << s[i] << ' ' << t[i] << ' ' << t .substr(i, ls) << endl;
if(i == 0 || t[i-1] == ' '){
if(s[0] == t[i] && t.substr(i, ls) == s && (t[i + ls] == ' ' || i + ls == lt - 1)){
cnt ++;
if(pos == -1) pos = i;
i = i + ls - 1;
}
}
}
if(pos != -1) cout << cnt << ' ' << pos;
else cout << pos;
system("pause");
return 0;
}
P2010 回文日期
只要枚举年份即可,反转前四位构成回文串再判断日期是否合法。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
char s[maxn], t[maxn];
int ans;
int main(){
scanf("%s", s); getchar();
scanf("%s", t);
int y1 = (s[0]-'0')*1000 + (s[1]-'0')*100 + (s[2]-'0')*10 + (s[3]-'0');
int y2 = (t[0]-'0')*1000 + (t[1]-'0')*100 + (t[2]-'0')*10 + (t[3]-'0');
int m1 = (s[4]-'0')*10 + s[5]-'0';
int m2 = (t[4]-'0')*10 + t[5]-'0';
int d1 = (s[6]-'0')*10 + s[7]-'0';
int d2 = (t[6]-'0')*10 + t[7]-'0';
for(int i = y1 ; i <= y2 ; ++ i){
string p = to_string(i);
int j = (p[3]-'0')*10+p[2]-'0';
int k = (p[1]-'0')*10+p[0]-'0';
if(j < 1 || j > 12 || k < 1 || k > 31) continue;
if(j == 4 || j == 6 || j == 9 || j == 11){
if(k >= 31) continue;
}
if(j == 2){
if(i % 400 == 0 || (i % 4 == 0 && i % 100 != 0)){
if(k > 29) continue;
}
else{
if(k >= 29) continue;
}
}
if(i == y1 && (j < m1 || (j == m1 && k < d1))) continue;
if(i == y2 && (j > m2 || (j == m2 && k > d2))) continue;
ans ++;
}
cout << ans;
system("pause");
return 0;
}
P1012 拼数
自定义排序。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
int n;
string s[30];
int cmp(string a, string b){
return a + b > b + a;
}
int main(){
cin >> n;
for(int i = 1 ; i <= n ; ++ i) cin >> s[i];
sort(s + 1, s + 1 + n, cmp);
for(int i = 1 ; i <= n ; ++ i) cout << s[i];
system("pause");
return 0;
}
P5587 打字练习
坑的一批,范文也有退格
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
string a[maxn], b[maxn];
string get_str(string p){
string x = "";
for(int j = 0 ; j < p.length() ; ++ j){
if(p[j] == '<'){
if(!x.empty()){
x.pop_back();
}
continue;
}
x = x + p[j];
}
return x;
}
int main(){
int la = 0, lb = 0;
while(1){
++ la;
getline(cin, a[la]);
if(a[la] == "EOF"){
la --; break;
}
}
while(1){
++ lb;
getline(cin, b[lb]);
if(b[lb] == "EOF"){
lb --; break;
}
}
int t;
cin >> t;
int ans = 0;
for(int i = 1 ; i <= min(la, lb) ; ++ i){
string x = get_str(a[i]);
string y = get_str(b[i]);
for(int j = 0 ; j < min(x.length(), y.length()) ; ++ j){
if(x[j] == y[j]) ans ++;
}
// cout << a[i] << " " << x << endl;
}
printf("%d", (int)(ans * 1.0 * 60 / t + 0.5));
system("pause");
return 0;
}
Part 1.4 函数,递归及递推
P1028 数的计算
记搜
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
int ans;
int record[maxn];
int dfs(int n){
// cout << n << endl;
if(record[n]){
return record[n];
}
for(int i = n / 2 ; i >= 1 ; -- i){
record[n] += dfs(i);
}
record[n] ++;
return record[n];
}
int main(){
int n;
cin >> n;
record[1] = 1;
cout << dfs(n);
system("pause");
return 0;
}
P1036 选数
写麻烦了,本来想降一下复杂度的。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
ll sum;
int n, k, prime, ans;
int vis[30];
ll a[maxn];
void dfs(int num, int f, ll he, int s){
if(num == (f == 0 ? 20 - k : k)){
if(f){
prime = 1;
for(int i = 2 ; i * i <= he ; ++ i){
if(he % i == 0){
prime = 0;
break;
}
}
if(prime) ans ++;
}
else{
prime = 1;
for(int i = 2 ; i * i <= he ; ++ i){
if((sum - he) % i == 0){
prime = 0;
break;
}
}
if(prime) ans ++;
}
}
for(int i = s ; i <= n ; ++ i){
if(!vis[i]){
vis[i] = 1;
dfs(num+1, f, he+a[i], i+1);
vis[i] = 0;
}
}
}
int main(){
cin >> n >> k;
for(int i = 1 ; i <= n ; ++ i){
cin >> a[i];
sum += a[i];
}
if(k > 10) dfs(0, 0, 0, 1);
else dfs(0, 1, 0, 1);
cout << ans;
system("pause");
return 0;
}
P1464 Function
记忆化搜索
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
ll a, b, c;
ll dp[21][21][21];
ll w(ll a, ll b, ll c){
if(a <= 0 || b <= 0 || c <= 0) return 1;
if(a > 20 || b > 20 || c > 20) return w(20, 20, 20);
if(dp[a][b][c]) return dp[a][b][c];
if(a < b && b < c) return dp[a][b][c] = w(a, b, c-1) + w(a, b-1, c-1) - w(a, b-1, c);
else return dp[a][b][c] = w(a-1, b, c) + w(a-1, b-1, c) + w(a-1, b, c-1) - w(a-1, b-1, c-1);
}
int main(){
while(scanf("%lld %lld %lld", &a, &b, &c)){
if(a==-1&&b==-1&&c==-1) break;
printf("w(%lld, %lld, %lld) = %lld\n", a, b, c, w(a, b, c));
}
system("pause");
return 0;
}
P5534 【XR-3】等差数列
公式
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
ll a, b, n;
int main(){
cin >> a >> b >> n;
cout << (a + a + (n-1)*(b-a)) * n / 2 << endl;
system("pause");
return 0;
}
P1192 台阶问题
类似于斐波那契
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int n, k;
int dp[maxn];
int main(){
cin >> n >> k;
dp[0] = 1;
for(int i = 1 ; i <= n ; ++ i){
for(int j = max(0, i-k) ; j < i ; ++ j){
dp[i] = (dp[j] + dp[i]) % 100003;
}
}
cout << dp[n];
system("pause");
return 0;
}
P1025 数的划分
dfs直接爆搜 or dp做
这题dp做还是很有意思的。数据增强版在这U101024 数的划分(数据加强版)
dfs爆搜解法
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 1e5 + 10;
int n, k, ans;
void dfs(int pos, int last, int sum){
if(pos == k - 1){
if(n - sum >= last) dfs(pos + 1, n - sum, n);
return;
}
if(sum == n && pos == k){
ans ++;
return;
}
for(int i = last ; i + sum <= n ; ++ i){
dfs(pos + 1, i, sum + i);
}
}
int main(){
cin >> n >> k;
dfs(0, 1, 0);
cout << ans;
system("pause");
return 0;
}
我们考虑dp解法。那么原题目分数字其实可以转换为$n$个球要放进$k$个盒子,但是不能有空盒的方案数。
那么我们考虑$dp[i][j]$代表把$i$个球放入$j$个盒子,且不空盒的方案数
那么要不空盒,朴素的思想就是先取$j$个球在每个盒子中都放入一个,然后再把剩下的$i-j$个球放入$j$个盒子
那么显然有:
\[dp[i][j] = \sum_{k=1}^j dp[i-j][k]\]这样子需要分别枚举$i,j,k$,时间复杂度为$O(nk^2)$ 注意在枚举的时候要保证$i>=j$,不然没法分。 代码如下
O(n*k*k)解法dp
cin >> n >> m;
for(int i = 0 ; i <= n ; ++ i) dp[i][1] = 1;
for(int i = 2 ; i <= n ; ++ i){
for(int j = 2 ; j <= m ; ++ j){
for(int k = 1 ; k <= j ; ++ k){
if(i >= j)
dp[i][j] += dp[i-j][k];
}
}
}
cout << dp[n][m];
但是其实还可以进一步优化到时间复杂度为$O(nk)$ 对于上述转移方程我们考虑:
\[dp[i-1][j-1] = \sum_{k=1}^{j-1} dp[i-j][k]\]等式右半之所以还是$i-j$是因为$(i-1) - (j-1) = i-j$
不难发现$dp[i][j]$和$dp[i-1][j-1]$只差了一项$dp[i-j][j]$
那么转移方程可以改写为:
\[dp[i][j] = dp[i-1][j-1] + dp[i-j][j]\]此时只需要两层循环即可。
O(n*k)解法dp
for(int i = 0 ; i <= n ; ++ i) dp[i][1] = 1;
for(int i = 2 ; i <= n ; ++ i){
for(int j = 2 ; j <= m ; ++ j){
if(i >= j) dp[i][j] = dp[i-j][j] + dp[i-1][j-1];
}
}
cout << dp[n][m];
但是对于强化版本的U101024 数的划分(数据加强版)我们还需要进一步优化空间复杂度才行。
其实因为k最大=600,所以每次更新dp数组只需要前面600个状态即可,这里考虑滚动数组来优化空间。
O(n*k)时间,O(k*k)空间解法dp
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
int n, m;
short dp[601][601];
int pos(int x){
return (x % 600) + 1;
}
int main(){
cin >> n >> m;
dp[pos(0)][0] = 1;
for(int i = 1 ; i <= n ; ++ i){
memset(dp[pos(i)], 0, sizeof(dp[pos(i)]));
for(int j = 1 ; j <= m && j <= i ; ++ j){
dp[pos(i)][j] = (dp[pos(i-j)][j] + dp[pos(i-1)][j-1])%10086;
}
}
cout << dp[pos(n)][m];
system("pause");
return 0;
}
P4994 终于结束的起点
因为斐波那契循环节$<=6n$,所以暴力即可。
展开代码
#include <bits/stdc++.h>
#define endl '\n'
#define ll long long
#define PB push_back
#define POP pop_back
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 2e5 + 10;
int n;
int a[3];
int main(){
cin >> n;
a[0] = 1; a[1] = 1;
for(int i = 2 ; ; ++ i){
if(a[0] == 0 && a[1] == 1){
cout << i - 1;
break;
}
a[2] = (a[0] + a[1]) % n;
a[0] = a[1];
a[1] = a[2];
}
system("pause");
return 0;
}
本站总访客数人次