约瑟夫问题
f(1,1) = 0 + 1;
f(n,k) = ( f(n-1,k) + k )%n + 1;
#include<cstdio>
int n,k;
int main(){
scanf("%d%d",&n,&k);
if(n==0){
printf("0"); return 0;
}
int ans=0;
for(int i=2;i<=n;i++)
ans=(ans+k)%i;
printf("%d",ans+1);
return 0;
离散化
将任何不在合适区间的整数或者非整数转化为不超过元素大小的整数
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=10010;
struct Node{
int val,pos;
}temp[maxn];
int A[maxn];//存放离散化之后的原始函数
bool cmp(Node a,Node b){
return a.val<b.val;
}
int main(){
int n=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&temp[i].val);
temp[i].pos=i;
}
sort(temp,temp+n,cmp);
for(int i=0;i<n;i++){
if(i==0||temp[i].val!=temp[i-1].val)
A[temp[i].pos]=i+1;
else
A[temp[i].pos]=A[temp[i-1].pos];
}
for(int i=0;i<n;i++) printf("%d ",A[i]);
return 0;
}
n个数的全排列
- 不含相同元素(dfs法)
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector< vector<int> > ans;
vector<int> tmp;
int n,num[1000];
bool vis[1000]={false};
void dfs4(int u){
if(u==n){
ans.push_back(tmp);
return ;
}
for(int i=0;i<n;i++){
if(!vis[i]){
//path[u]=num[i];
tmp.push_back(num[i]);
vis[i]=true;
dfs4(u+1);
tmp.pop_back();
vis[i]=false;
}
}
}
int main(){
scanf("%d%d",&n,&tg);
for(int i=0;i<n;i++)
scanf("%d",&num[i]);
sort(num,num+n);
dfs4(0);
for(int i=0;i<ans.size();i++){
for(int j=0;j<ans[i].size();j++)
printf("%d ",ans[i][j]);
printf("\n");
}
return 0;
}
- 含有重复元素
void dfs3(int u){
if(u==n){
ans.push_back(tmp);
return ;
}
for(int i=0;i<n;i++){
//将重复元素当作一个元素处理,只有在它之前的重复元素已经被访问,他才可以访问
if(i==0||num[i-1]!=num[i]||num[i-1]==num[i]&&vis[i-1]){
if(!vis[i]){
vis[i]=true;
tmp.push_back(num[i]);
dfs3(u+1);
tmp.pop_back();
vis[i]=false;
}
}
}
}
- n个数的全排列(SLT)
#include<cstdio>
#include<algorithm>
using namespace std;
int main(){
int n,a[1000];
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
sort(a,a+n);
do{
for(int i=0;i<n;i++) printf("%d ",a[i]);
printf("\n");
}while(next_permutation(a,a+n));
return 0;
}
单调队列
参考:单调队列的deque实现
单调队列常用于解决滑动窗口中的最值问题
vector<int> maxSlidingWindow(vector<int>& num, int k) {
vector<int> res;
int n=nums.size();
deque<int> q;
for(int i=0;i<n;i++){
while(!q.empty()&&i-q.front>=k) q.pop_front();//删除越界元素
while(!q.empty()&&nums[i]>=nums[q.back()]) q.pop_back();//保持队列为递减数列
q.push_back(i);
if(i>=k-1)//达到k的窗口大小
res.push_back(nums[q.front()]);
}
return res;
}
- 区间长度不大于m的最大序列和
#include<cstdio>
#include<deque>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int a[N],sum[N];
struct node{
int order; int value;
}tmp;
deque<node> q;
int main(){
int n,m,ans;
while(1==1){
q.clear();
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
if(i==0) sum[i]=a[i];
else sum[i]=sum[i-1]+a[i];
if(!q.empty()&&i-q.front().order>m)
q.pop_front();//>m
while(!q.empty()&&q.back().value>sum[i])
q.pop_back();//必须保证队首的sum最小
tmp.value=sum[i];
tmp.order=i;
q.push_back(tmp);
if(i==0) ans=sum[i];
else ans=max(ans,sum[i]-q.front().value);
}
printf("%d",ans);}
return 0;
}
单调栈
利用单调栈,可以找到从左/右遍历第一个比它小/大的元素的位置。例如,在递增栈中,元素向左遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,若栈为空,则说明不存在这么一个数。
例题:给定两个没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个(右边第一个)比其大的值。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-i
#include<cstdio>
#include<map>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=10000;
int num1[maxn],num2[maxn],n1,n2;
stack<int> st;//栈顶为最小元素
map<int,int> mp;//元素-》较大值
int main(){
scanf("%d%d",&n1,&n2);
for(int i=0;i<n1;i++)
scanf("%d",&num1[i]);
for(int i=0;i<n2;i++)
scanf("%d",&num2[i]);
for(int i=0;i<n2;i++){
while(!st.empty()&&num2[i]>st.top()){
mp[st.top()]=num2[i];
st.pop();
}
st.push(num2[i]);
}
for(int i=0;i<n1;i++)
printf("%d ",mp[num1[i]]);
return 0;
}
dfs应用
- 和为tg的组合数(序列中不含重复元素,每个数只能取一次)
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector< vector<int> > ans;
vector<int> tmp;
int n,num[1000],tg;
void dfs2(int index,int sum){//dfs2(0,0);
if(sum==tg){
ans.push_back(tmp);
return ;
}else if(index==n||sum>tg){
return ;
}else{
tmp.push_back(num[index]);
dfs2(index+1,sum+num[index]);///111111111
tmp.pop_back();
dfs2(index+1,sum);
}
}
!!!若可以多次取数字,则(1)处改为dfs2(index,sum+num[index]);
- 和为tg的组合数(序列中含重复元素,一个元素取一次)
void dfs1(int index,int sum){
if(sum==tg){
ans.push_back(tmp);
return ;
}else if(sum>tg){
return ;
}else{
for(int i=index;i<n;i++){
if(i&&i>index&&num[i-1]==num[i])//将重复情况进行剪枝
continue;
tmp.push_back(num[i]);
dfs1(i+1,sum+num[i]);
tmp.pop_back();
}
}
}