题解
A B2045 晶晶赴约会 B2045 晶晶赴约会 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
奇数有课,偶数没课,7单判
AC代码
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n ;cin>>n; if(n % 2 && n != 7) cout << "NO"<<endl;//同时满足即可 else cout <<"YES"<<endl; return 0; }
B B2082 数字统计B2082 数字统计 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
从L 遍历到 R 使用to_string转为字符串,然后count来计数就行了
第一遍交的时候,从0开始遍历了。。。。。
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int l , r , cnt = 0; cin >> l >> r; for (int i = l ; i <= r ; i++){ string s = to_string(i); cnt += count(s.begin() , s.end() , '2');//count, 第一个参数是要查询区间的起始位置,第二个是终点位置,因为字符串的每个字符都要判断,所以用迭代器了,第三个参量是要查询的字符 } cout << cnt <<endl; return 0; }
C B2140 二进制分类B2140 二进制分类 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
枚举每个数字,判断是否是A类数字,使用位运算判断每一位是否为1即可
不想在外部写函数了,正好在刷leetcode时看见了function的奇妙用法,顺便试试
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //枚举每个数字 int n , ans = 0; cin >> n; //Lambda + function 实现内部函数 function<bool(int)> cnt = [](int x){ int c = 0 , d = 0;//c记录 1 的个数, d记录0的个数 while(x){ if(x&1) c++; else d++; x>>=1;//移位 111 -> 011 -> 001 -> 000 } return c > d; }; for (int i = 1 ; i <= n ; i++){ if(cnt(i)) ans++; } cout << ans << ' ' << n - ans <<endl; return 0; }
D B2110 找第一个只出现一次的字符B2110 找第一个只出现一次的字符 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
将字符串中的每个字母的出现次数记录下来,再遍历一遍,找到第一个出现次数为1的字符
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int cnt[26]; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); string s ; cin >> s; //统计每个字母出现个数 for (int i = 0 ; i < s.size() ; i++){ cnt[s[i] - 'a'] ++;//减去字符'a'即可把26个小写字母映射到0~25这个下标中 } for (int i = 0 ; i < s.size() ; i++){ if (cnt[s[i] - 'a'] == 1){//找到第一个只出现一次的字母,输出 cout << s[i] << endl; return 0; } } cout << "no" <<endl;//没找到输出no return 0; }
E P1259 黑白棋子的移动P1259 黑白棋子的移动 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
观察规律,假设下标从1开始,那么下标为1 -- n*2 + 2,最后两个字符是空行
就是每一次都要交换空行的两个字符和相邻的两个不同的棋子(最后四组不同)
双指针指向左边第一个要交换的和右边第一个要交换的字符
第一次交换的是{n-1,n} 和{2n-1,2n}
第二次{n-1,n}和{2n-2,2n-1}
以此类推,可以得到,左边交换的下标往左移1位和右边下标往左移2位是轮流的,那么就可以用一个cnt来记录次数,实现反复移动
但是当左界下标移动到4的时候,就不一样了,看不出来规律,直接按样例来进行移动下标了
感觉是这里面最难的了
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //看实例:明显,每次都是再交换相邻的两个不通的黑白棋与空行 //之后通过将空格换回到上一次之前的位置,能够再次得到一对相邻的黑白棋,重复交换即可得到答案 int n ; cin >> n; vector<char> a(2*n + 3); function<void()> print = [&](){ for (int i = 1 ; i <= 2*n +2 ; i ++){//下表为0的元素没有使用到 cout << a[i] ; } cout << '\n'; return ; }; //初始化,前n个为o , n+1 到 2n为*,最后还有两个空行字符 for (int i = 1 ; i <= 2*n + 3 ; i++){ if(i <= n ) a[i] = 'o'; else if (i <= 2*n) a[i] = '*'; else a[i] = '-'; } print(); //左边该交换的第一个字符和右边该交换的第一个字符的下标 int l = n ,r = 2*n + 1; int cnt = 0; //记录交换次数,来实现轮流处理l和r while(l>4){ swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); cnt ++; if(cnt % 2 == 0) l--; else r-=2; print(); } //最后四个采用样例的处理 swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); print(); r--; swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); print(); l-=2; swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); print(); r--; swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); print(); l--; swap(a[l] , a[r]); swap(a[l + 1] , a[r + 1]); print(); return 0; }
F P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题P1029 [NOIP2001 普及组] 最大公约数和最小公倍数问题 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
枚举P,Q统计结果,P,Q都是在x0--y0区间的
枚举P,通过最小公倍数计算出Q,验证是否满足最大公约数和做小公倍数的那个条件
注意到:c++的除法是向下取整的,所以要注意点
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; //递归实现欧几里得算法求最大公约数 int gcd(int a , int b){ return b ? gcd(b , a % b) :a; } //递归求最小公倍数 int lcm(int a,int b){ return a*b/gcd(a,b); } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //枚举P,Q统计结果,P,Q都是在x0--y0区间的 //枚举P,通过最小公倍数计算出Q,验证是否满足最大公约数那个条件 int x , y , ans = 0 ,cnt = 0; cin >> x >> y; //枚举p的取值 for (int p = x ; p <= y; p++){ int q = y*x/p;//计算出q //注意到因为向下取整,所以q有可能不能与p满足最小公倍数的条件,所以都判断一边了 if( gcd(p,q) == x &&lcm(p,q) == y) ans ++ ; } cout << ans <<endl; return 0; }
G P1604 B进制星球P1604 B进制星球 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
首先:
数据最长有2000位,所以要进行加法的话必须要用高精度算法
当n大于10时要处理字母
每一位计算时转化为10进制进行计算,而且不会爆int
输出的时候要转化回去而且逆序输出
最开始没看见2000位
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //首先: //输入中可能存在字符,所以采用读入字符串的方式来读取 //将数字转化为十进制计算之后再转化回去就可以了 //注意到刚好 26个大写字母都有可能用到 //两千位要用高精度,而且也不能转为10进制算了 //转换:16进制大于9的本分转换为十进制, x - 'A' + 10 // 10转16 y + 'A' - 10 ll n ,x = 0, y = 0 , len; string a,b; vector<char> A,B; cin >> n >> a >> b; function <vector<char> (vector<char> , vector<char>)> add = [&](vector<char> A ,vector<char> B){ if(A.size()<B.size()) return add(B,A); vector<char> C; int t=0; //t用来记录每一个位置上的数据大小 for(int i=0;i<A.size();i++){ //将每位数字转化为10进制,最大也会是 15 + 15 = 30 不会 if(A[i] >= 'A') t +=A[i] - 'A' + 10; else t += A[i] - '0'; if(i<B.size()){ if(B[i] >= 'A') t+=B[i] - 'A' + 10; else t += B[i] - '0'; } int p = t % n;//当前位置上的数字 if (p >= 10) C.push_back(p - 10 + 'A');//p>=10 说明是十进制以上了,要处理 else C.push_back(p + '0'); t/=n;//进位 } if(t) C.push_back('1');//最后一个如果不等于0,说明还要进一个位 return C; }; //逆序存入,方便进行进位 for(int i=a.size()-1;i>=0;i--){ A.push_back(a[i]); } for(int i=b.size()-1;i>=0;i--){ B.push_back(b[i]); } vector<char> C = add(A,B); //逆序存的所以要逆序输出 for(int i=C.size()-1;i>=0;i--){ cout << C[i]; } return 0; }
H P1060 [NOIP2006 普及组] 开心的金明P1060 [NOIP2006 普及组] 开心的金明 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:
01背包
状态定义:
dp[i][j] 表示 以i为下标(序号),的容量(价格)为j的情况下所能得到的最大值
状态转移:
当前物品购入 :
dp[i][j] = dp[i-1][j - v[i]] + v[i] *w[i]
由前一个序号的状态进行转移,同时需要留出能够容纳当前物品价格的空间
当前物品不购入:
dp[i][j] = dp[i-1][j]
直接由前一个状态转移即可两者取最大
优化空间:注意到每一次转移都只用到了前一个状态,即不需要将每一个状态都保存
所以可以压缩为一维DP
dp[j] = max(dp[j] , dp[j - v[i]] + v[i] *w[i])
AC代码:
#include <bits/stdc++.h> #define ll long long #define pii pair<int,int> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); //状态分析:dp[i][j] 第i个序号所对应的为j的价格能得到的价值 //最大值 //状态转移:dp[i][j] = max(dp[i][j] , dp[i][j- v[i]] + w[i]) //状态转移:dp[i][j] = max(dp[i - 1][j] , dp[i - 1][j- v[i]] + w[i]) //状态压缩,每次只用到 dp[i-1] 这个位置,所以用滚动数组 dp[j] = max(dp[j], dp[j - v[i]] + v[i] * w[i]); ll n , m;//防止爆int cin >> m >> n; // m 为价格, n为个数 vector<ll> dp(m+1);// 价格容量为0 - m vector<ll> v(n + 1) , w(n + 1); for (int i = 1 ; i <= n ; i++){ cin >> v[i] >> w[i] ; } ll ans = 0; for (int i = 1 ; i <= n ; i++){ for (int j = m ; j >= v[i] ; j--){ dp[j] = max(dp[j] , dp[j - v[i]] + w[i] * v[i]); } } cout << dp[m] <<endl; return 0; }
给未来大一萌新看的