一、笨小猴(哈希+数学)


cpp
#include <iostream>
#include <cmath>
using namespace std;
string s;
bool isprime(int x){
//试除法
if(x==2) return true;
if(x<2||x%2==0) return false;
int n=sqrt(x);
for(int i=3;i<=n;i+=2)
if(x%i==0) return false;
return true;
}
int main() {
cin>>s;
int hash[26]={0};//哈希表
for(auto&ch:s) ++hash[ch-'a'];
int maxn=0,minn=100;
for(int i=0;i<26;++i)//找最大值和最小值
if(hash[i]){
maxn=max(maxn,hash[i]);
minn=min(minn,hash[i]);
}
int x=maxn-minn;
if(isprime(x)) {
cout<<"Lucky Word"<<endl;
cout<<x<<endl;
}
else {
cout<<"No Answer"<<endl;
cout<<0<<endl;
}
}
二、主持人调度(左端点排序)


cpp
class Solution {
public:
bool hostschedule(vector<vector<int> >& schedule) {
sort(schedule.begin(),schedule.end());
int n=schedule.size();
for(int i=0;i<n-1;++i)
if(schedule[i][1]>schedule[i+1][0]) return false;
return true;
}
};
三、分割等和子集(01背包)


cpp
#include <iostream>
using namespace std;
//从数组中挑选一些数字 是否可以恰好等于sum/2 01背包问题
int n;
const int N=505,M=505*105/2;
int arr[N];
bool dp[M];
int main(){
cin>>n;
int sum=0;//记录总和
for(int i=1;i<=n;++i){
cin>>arr[i];
sum+=arr[i];
}
if(sum%2) cout<<"false"<<endl;//不能整除
else{
sum/=2;
dp[0]=true;
for(int i=1;i<=n;++i)
for(int j=sum;j>=arr[i];--j)
dp[j]=dp[j]||dp[j-arr[i]];
if(dp[sum]) cout<<"true"<<endl;
else cout<<"false"<<endl;
}
}
四、小红的ABC(找规律)


cpp
//a b c三个字母 最短的 那么只有可能是2和3
#include<iostream>
#include<string>
using namespace std;
string s;
int main(){
cin>>s;
int n=s.size();
int ret=-1;//没有回文串的情况
for(int i=0;i<n-1;++i){
if(s[i]==s[i+1]){
ret=2;
break;
}
if(i+2<n&&s[i]==s[i+2]) ret=3;
}
cout<<ret<<endl;
}
五、不相邻取数(状态dp)


cpp
#include <iostream>
using namespace std;
const int N=2e5+10;
int n;
int arr[N],f[N],g[N];//f[i]是选了i位置后的最大 g[i]是没选i位置后的最大
int main() {
cin>>n;
for(int i=1;i<=n;++i) cin>>arr[i];
for(int i=1;i<=n;++i){
f[i]=g[i-1]+arr[i];
g[i]=max(f[i-1],g[i-1]);
}
cout<<max(f[n],g[n])<<endl;
}
六、**空调遥控(排序+二分/滑动窗口)



解法1:排序+二分找区间(左端点+右端点组合)
cpp
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int arr[N];
int n,p;
int main(){
cin>>n>>p;
for(int i=0;i<n;++i) cin>>arr[i];
sort(arr,arr+n);
int ret=1;
//开始枚举
for(int i=arr[0];i<=arr[n-1];++i){//枚举温度
int left=0,right=n-1;
while(left<right){//begin-2 用左端点区间
int mid=left+(right-left)/2;
if(arr[mid]<i-p) left=mid+1;
else right=mid;
}
int begin=left;
right=n-1;//left可以继续从原来的位置找 重置right就行了
while(left<right){//begin-p 用右端点区间
int mid=left+(right-left+1)/2;
if(arr[mid]<=i+p) left=mid;
else right=mid-1;
}
ret=max(ret,right-begin+1);
}
cout<<ret<<endl;
return 0;
}
解法2:滑动窗口
cpp
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int arr[N];
int n,p;
int main(){
cin>>n>>p;
p*=2;//差值
for(int i=0;i<n;++i) cin>>arr[i];
sort(arr,arr+n);
//滑动窗口 差值在2*p的最大区间
int ret=1;
for(int left=0,right=0;right<n;++right){
while(arr[right]-arr[left]>p)++left;
ret=max(ret,right-left+1);
}
cout<<ret<<endl;
}
七、kotori和气球(组合数学)


cpp
#include<iostream>
using namespace std;
const int mod=109;
int n,m;
int main(){
cin>>n>>m;
//n与m个(n-1)的乘积
int ret=n;
for(int i=0;i<m-1;++i) ret=ret*(n-1)%mod;
cout<<ret<<endl;
}
八、 *走迷宫(单源最短路BFS)
单源最短路问题:

cpp
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
const int N=1010;
int dx[4]={0,0,-1,1};
int dy[4]={-1,1,0,0};
int n,m,x1,x2,y1,y2;
char arr[N][N];
int dis[N][N];//不仅用来看看搜索过了没
//单源最短路问题 用bfs扩展
int bfs(){//-1表示走不到
if(arr[x2][y2]=='*') return -1;
memset(dis, -1, sizeof dis); // 表⽰还没开始搜索
queue<pair<int,int>> q;
q.emplace(x1,y1);
dis[x1][y1]=0;
while(!q.empty()){
auto[a,b]=q.front();
q.pop();
for(int k=0;k<4;++k){
int x=dx[k]+a,y=dy[k]+b;
if(x>=1&&x<=n&&y>=1&&y<=m&&arr[x][y]=='.'&&dis[x][y]==-1){
q.emplace(x,y);
dis[x][y]=dis[a][b]+1;
if(x==x2&&y==y2) return dis[x][y];
}
}
}
return -1;
}
int main() {
cin>>n>>m>>x1>>y1>>x2>>y2;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) cin>>arr[i][j];
cout<<bfs()<<endl;
}
1、读取定长字符串也可以按照字符一个个读取
2、单源最短路的标记数组不仅可以记录距离,也可以用来标记是否搜索过
3、memset用来标记-1
九、**主持人调度2(贪心+优先级队列+左端点排序)

解法1:贪心+优先级队列+左端点排序
cpp
class Solution {
public:
int minmumNumberOfHost(int n, vector<vector<int>>& startEnd) {
sort(startEnd.begin(),startEnd.end());
priority_queue<int,vector<int>,greater<int>> heap;//创建一个小根堆
heap.push(startEnd[0][1]);
for(int i=1;i<n;++i){
int a=startEnd[i][0],b=startEnd[i][1];
if(a>=heap.top()) heap.pop(); //说明没有重叠
heap.push(b);
}
return heap.size();
}
};
解法2:分别排序+遍历比较
cpp
class Solution {
public:
int minmumNumberOfHost(int n, vector<vector<int> >& startEnd) {
vector<int> start;
vector<int> end;
//分别得到活动起始时间
for(int i = 0; i < n; i++){
start.push_back(startEnd[i][0]);
end.push_back(startEnd[i][1]);
}
//分别对开始和结束时间排序
sort(start.begin(), start.end());
sort(end.begin(), end.end());
int res = 0;
int j = 0;//遍历结束时间
for(int i = 0; i < n; i++)
//新开始的节目大于上一轮结束的时间,主持人不变
if(start[i] >= end[j]) j++;
else res++; //主持人增加
return res;
}
};
十、游游的重组偶数(数学)

cpp
#include <iostream>
#include <string>
using namespace std;
//把每个数字中为偶数的部分放到最后就可以了
int q;
string s;
int main() {
cin>>q;
while(q--){
cin>>s;
int n=s.size();
int i=n-1;
for(;i>=0;--i)
if(s[i]%2==0){
swap(s[i],s[n-1]);
break;
}
if(i!=-1) cout<<s<<endl;
else cout<<-1<<endl;
}
}
十一、**体操队形(枚举+dfs)


cpp
#include<iostream>
using namespace std;
int n;
int ret=0;//统计最终结果
const int N=11;
int arr[N];
bool vis[N];//队员
void dfs(int pos){
if(pos==n+1){
++ret;
return;
}//说明找到了一种合法方案
//开始一个个位置去选择
for(int i=1;i<=n;++i){
if(vis[i]) continue;//如果该位置的人选过了 就跳过
//我不可能排在我想排的人前面 那后面再怎么选都是错的
if(vis[arr[i]]) return;
vis[i]=true;
dfs(pos+1);
vis[i]=false;
}
}
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>arr[i];
dfs(1);//从第一个位置开始选
cout<<ret<<endl;
}
十二、**二叉树中的最大路径和(dfs+树形dp思想)
cpp
class Solution {
public:
int ret=-1010;//统计最大值
int maxPathSum(TreeNode* root) {
dfs(root);
return ret;
}
int dfs(TreeNode* root){
if(root==nullptr) return 0;
int left=max(dfs(root->left),0);//最大左子链
int right=max(dfs(root->right),0);//最大右子链
ret=max(ret,left+right+root->val);//经过root的最大路径
return root->val+max(left,right);//给上层返回单链的信息
}
};
十三、*排序子序列(模拟+贪心)


cpp
#include <iostream>
using namespace std;
int n;
const int N=1e5+10;
int arr[N];
int main() {
cin>>n;
for(int i=0;i<n;++i) cin>>arr[i];
int ret=0,i=0;
while(i<n){
if(i==n-1){//这个时候不存在后面的数比了 所以自己就是一个子序列
++ret;
break;
}
if(arr[i+1]>arr[i]){//搞一个上升的子序列
while(i+1<n&&arr[i+1]>=arr[i]) ++i;
++ret;
}
else if(arr[i+1]<arr[i]){//说明搞一个下降的子序列
while(i+1<n&&arr[i+1]<=arr[i]) ++i;
++ret;
}
else while(i+1<n&&arr[i+1]==arr[i]) ++i;
++i;
}
cout<<ret<<endl;
}
十四、消减整数(贪心+数学)


cpp
#include<iostream>
using namespace std;
//得确保 正好a*2==cur 才可以翻倍
int t,h;
int main(){
cin>>t;
while(t--){
cin>>h;
int a=1,ret=0;
while(h){
h-=a;
++ret;
if(h%(a*2)==0) a*=2;
}
cout<<ret<<endl;
}
}
十五、最长上升子序列2(贪心+二分)
cpp
class Solution {
public:
int LIS(vector<int>&nums) {
int n=nums.size();
if(n<=1) return n;
//至少有两个元素
vector<int> v;//用来当数组
v.emplace_back(nums[0]);
for(int i=1;i<n;++i){
int x=nums[i];
//如果比后面的大 就直接插入
if(x>v.back()) v.emplace_back(nums[i]);
else if(x==v.back()) continue;
else{//二分查找插入的位置
int left=0,right=v.size()-1;
while(left<right){
int mid=left+(right-left)/2;
if(v[mid]<x) left=mid+1;
else right=mid;
}
v[left]=x;
}
}
return v.size();
}
};
十六、爱吃素(数学)


cpp
#include<iostream>
#include<cmath>
using namespace std;
int t;
typedef long long LL;
LL a,b;
bool isprim(LL x){
if(x==2) return true;
if(x<2||x%2==0) return false;
int n=sqrt(x);
for(int i=3;i<=n;i+=2)
if(x%i==0) return false;
return true;
}
int main(){
cin>>t;
while(t--){
cin>>a>>b;
if((a==1&&isprim(b))||(b==1&&isprim(a))) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
十七、相差不超过k的最多数(排序+滑动窗口)


cpp
#include <iostream>
#include <algorithm>
using namespace std;
int n,k;
const int N=2e5+1;
int arr[N];
int main() {
cin>>n>>k;
for(int i=0;i<n;++i) cin>>arr[i];
sort(arr,arr+n);
int ret=1;
for(int left=0,right=0;right<n;++right){
while(arr[right]-arr[left]>k) ++left;
ret=max(right-left+1,ret);
}
cout<<ret<<endl;
}
十八、最长公共子序列1(LCSdp)
cpp
#include <iostream>
using namespace std;
const int N=1010;
char s1[N],s2[N];
int dp[N][N];
int n,m;
int main() {
//dp[i][j]表示以0-i的字符串1中 与0-j字符串2中 的最长公共子序列长度
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>s1[i];
for(int i=1;i<=m;++i) cin>>s2[i];
//开始进行dp
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(s1[i]==s2[j]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
cout<<dp[n][m]<<endl;
}
