动态规划
[模板]01背包
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
struct node
{
int val,vol;
}item[maxn];
int n,m;
int dp[maxn];
void _01backpack()
{
for(int i=1;i<=n;i++)
{
for(int j=m;j>=item[i].vol;j--)
{
dp[j]=max(dp[j],dp[j-item[i].vol]+item[i].val);
}
}
}
[模板]LDS和LIS
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
int a[maxn];
int d[maxn];
int LIS_LDS(int n)
{
int len;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
d[len=1]=a[1];
for(int i=2;i<=n;i++)
{
if(a[i]>d[len]) d[++len]=a[i];
else *lower_bound(d+1,d+1+n,a[i]) = a[i];//
}
return len;
}
/* 不同类型的最长XX子序列除了改变第四行的运算符号之外,第五行的代码也要相应变化:
最长上升子序列:查找大于等于 lower_bound(...)
最长下降子序列:查找小于等于 upper_bound(...,greater<int>())
最长不下降子序列LIS:查找大于 lower_bound(...)
最长不上升子序列LDS:查找小于 upper_bound(...,greater<int>()) */
[模板]LCS最长公共子序列
#include<bits/stdc++.h>
#define endl "\n"
#define pb push_back
#define ALL(x) x.begin(),x.end()
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
typedef pair<int,int> pii;
const int inf=INT_MAX;
const int mod=1e9+7;
const int maxn=1e3+7;
const int Maxn=1e5+7;
int n;
int dp[maxn][maxn];
int f[Maxn];
map<int,int> mp;
void LCS_1()//O(n^2)LCS朴素做法,只能到10^3的数据范围
{
cin>>n;
vector<int> a(n+1), b(n+1);
for(int i=1; i<=n; i++) cin>>a[i];
for(int i=1; i<=n; i++) cin>>b[i];
int len1=n,len2=n;
for(int i=1; i<=len1; i++)
{
for(int j=1; j<=len2; j++)
{
dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
if(a[i] == b[j])
{
dp[i][j] = max(dp[i][j],dp[i-1][j-1]+1);
}
}
}
cout<<dp[len1][len2]<<endl;//输出最长公共子序列的长度
}
void LCS_2()//O(nlogn) 大于10^5的数据范围
{
cin>>n;
vector<int> a(n+1),b(n+1);
for(int i=1;i<=n;i++)
{
cin >> a[i];
mp[a[i]]=i;
}
for(int i=1;i<=n;i++)
{
cin >> b[i];
f[i]=0x7fffffff;
}
int len=0;
f[0]=0;
for (int i=1; i<=n; i++)
{
int l=0, r=len, mid;
if(mp[b[i]] > f[len]) f[++len]=mp[b[i]];
else
{
while (l < r)
{
mid = (l+r)/2;
if(f[mid] > mp[b[i]]) r = mid;
else l = mid+1;
}
f[l] = min(mp[b[i]], f[l]);
}
}
cout<<len<<endl;//输出最长公共子序列的长度;
}
基本算法
[模板]高精度四则运算
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
string Addition(string a,string b)//高精度加法
{
int sa[1000]={0};
int sb[1000]={0};
int sc[1000]={0};
for(int i=1;i<=a.size();i++) sa[i]=a[a.size()-i]-'0';
for(int i=1;i<=b.size();i++) sb[i]=b[b.size()-i]-'0';
int Max=max(a.size(),b.size());
for(int i=1;i<=Max;i++)
{
sc[i]=sc[i]+sa[i]+sb[i];
sc[i+1]=sc[i]/10;
sc[i]=sc[i]%10;
}
if(sc[Max+1]!=0) Max++;
string s;
for(int i=Max;i>=1;i--)
{
s+=sc[i]+'0';
}
return s;
}
string Subtraction(string a,string b)//高精度减法
{
bool flag=false;
if((a.size()==b.size()&&a<b)||a.size()<b.size())
{
return "-"+Subtraction(b,a);
}
int na[10500]={0};
int nb[10500]={0};
int ans[10500]={0};
for(int i=a.size()-1;i>=0;i--) na[a.size()-i]=a[i]-'0';
for(int i=b.size()-1;i>=0;i--) nb[b.size()-i]=b[i]-'0';
int max1=max(a.size(),b.size());
for(int i=1;i<=max1;i++)
{
if(na[i]<nb[i])
{
na[i+1]--;
na[i]+=10;
}
ans[i]=na[i]-nb[i];
}
string s;
while(ans[max1]==0)
max1--;
if(max1<1)
{
return "0";
}
for(int i=max1;i>=1;i--)
s+=(ans[i]+'0');
return s;
}
string Multiplication(string a,string b)//高精度乘法
{
int sa[1000];
int sb[1000];
int sc[1000]={0};
for(int i=0;i<a.size();i++) sa[i]=a[a.size()-1-i]-'0';
for(int i=0;i<b.size();i++) sb[i]=b[b.size()-1-i]-'0';
int _max=a.size()+b.size();
for(int i=0;i<a.size();i++)
{
for(int j=0;j<b.size();j++)
{
sc[i+j]+=sa[i]*sb[j];
sc[i+j+1]+=(sc[i+j])/10;
sc[i+j]=sc[i+j]%10;
}
}
while(sc[_max-1]==0&&_max>1) _max--;
string s;
for(int i=_max-1;i>=0;i--)
{
s+=sc[i]+'0';
}
return s;
}
[模板]前缀和
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+7;
class One_Dimension//一维
{
int a[maxn];
int pre[maxn];
int n;
void Create()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
pre[i]=pre[i-1]+a[i];
}
}
int Sum_interval(int l,int r)//l左端点,r右端点
{
return pre[r]-pre[l-1];
}
};
class Double_Dimension//二维
{
int a[maxn][maxn];
int pre[maxn][maxn];
int n;
void Create()
{
cin>>n;
for (int i=1; i<=n; i++)
{
for (int j=1; j<=n; j++)
{
cin >> a[i][j];
pre[i][j]=pre[i-1][j]+pre[i][j-1]-pre[i-1][j-1]+a[i][j];
}
}
}
int Sum_interval(int i,int j,int k,int l)//从 左上(k,l) 到 右下(i,j) 的和
{
return pre[i][j]-pre[k-1][j]-pre[i][l-1]+pre[k-1][l-1];
}
};
数据结构
[模板]单调队列
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int maxn=1e5+7;
void Priority_queue(vector<int>& v)
{
priority_queue<pll,vector<pll>,less<pll> > q1;
priority_queue<pll,vector<pll>,greater<pll> > q2;
vector<ll> ans1,ans2;//ans1为最大值,ans2为最小值
int n,k;
cin>>n>>k;//n个数,每次扫描k个数据
for(int i=1;i<=n;i++)
cin>>v[i];
for(int i=1;i<=n;i++)
{
pll temp={v[i],i};
q1.push(temp);
q2.push(temp);
if(i>=k)//判断范围
{
while(q1.top().second<=i-k)
q1.pop();
ans1.push_back(q1.top().first);
while(q2.top().second<=i-k)
q2.pop();
ans2.push_back(q2.top().first);
}
}
for(auto i:ans2)
cout<<i<<" ";
cout<<endl;
for(auto i:ans1)
cout<<i<<" ";
}
[模板]单调栈
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
void priority_stack(vector<int>& v)
{
v.push_back(INT_MAX);
stack<int> st;
int sum = 0;
for (int i=0; i<v.size(); i++)
{
if (st.empty() || v[st.top()] > v[i])
st.push(i);
else
{
while (!st.empty() && v[st.top()] <= v[i])
{
int top = st.top();
st.pop();
}
st.push(i);
}
}
}
[模板]ST表
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const int pows=21;
int st_max[maxn][pows+1];
int st_min[maxn][pows+1];
int query_max(int l,int r)//查询最大
{
int len=log2(r-l+1);
return max(st_max[l][len],st_max[r-(1<<len)+1][len]);
}
int query_min(int l,int r)//查询最小
{
int len=log2(r-l+1);
return min(st_min[l][len],st_min[r-(1<<len)+1][len]);
}
void ST()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)//对于i,从i开始的2^0个数的最值就是其本身
{
int temp;
cin>>temp;
st_max[i][0]=temp;
st_min[i][0]=temp;
}
for(int j=1; j<=pows; j++)//对st表的处理
{
for(int i=1; i+(1<<j)<=n+1; i++)
{
st_max[i][j]=max(st_max[i][j-1],st_max[i+(1<<(j-1))][j-1]);
st_min[i][j]=min(st_min[i][j-1],st_min[i+(1<<(j-1))][j-1]);
}
}
}
[模板]树状数组
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int tree[maxn];
int c[maxn];//c是原数组的差分数组
int n;
int lowbit(int x)//最低位的1
{
return x&(-x);
}
void add_point(int x,int k)//单点修改,树状数组单点修改,对tree[x]操作
{
for(int i=x;i<=n;i+=lowbit(i))
tree[i]+=k;
}
ll ask_interval_1_X(int x)//区间查询,查询[1,x]的区间和
{
ll sum=0;
for(int i=x; i; i-=lowbit(i))
{
sum += tree[i];
}
return sum;
}
ll ans_interval_L_R(int L,int R)//区间查询,查询[L,R]的区间和,方法:[L,R]=[1,R]-[L-1,R];
{
ll ans=0;
for(int i = R; i>0; i -= lowbit(i))
{
ans += tree[i];
}
for(int i = L-1; i>0; i -= lowbit(i))
{
ans -= tree[i];
}
return ans;
}
void update(int pos,int k)//区间修改,对区间[L,R]+k,那么我们只需要更新差分数组update(L,k),update(R+1,-k)
{
for(int i=pos; i<=n; i += lowbit(i))
{
c[i] += k;
}
}
//[L,R]+k = update(L,k) , update(R+1,-k);
ll ask(int pos)//单点查询,返回[pos,1]的总和
{
ll ans=0;
for(int i=pos; i; i -= lowbit(i)) ans += c[i];
return ans;
}
[模板]线段树
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e5+10;
struct node
{
int l,r,lz,mlz;
ll sum;
}tree[maxn];
int input[maxn];
ll ans;
inline void push_down(int i)
{
if(tree[i].lz!=0)
{
tree[i*2].lz+=tree[i].lz;//左右儿子分别加上父亲的lz
tree[i*2+1].lz+=tree[i].lz;
int mid=tree[i].l + tree[i].r >> 1;
tree[i*2].sum += tree[i].lz * (mid - tree[i*2].l + 1);//左右分别求和加起来
tree[i*2+1].sum += tree[i].lz * (tree[i*2+1].r - mid);
tree[i].lz = 0;//父亲lz归零
}
return;
}
inline void build(int i, int L, int R)//建树
{
tree[i].l=L;
tree[i].r=R;
if(L==R)//如果这个节点是叶子结点
{
tree[i].sum=input[L];
return;
}
int mid=(L+R)>>1;
build(i*2,L,mid);
build(i*2+1,mid+1,R);
tree[i].sum=tree[i*2].sum+tree[i*2+1].sum;
}
inline int search(int i,int L,int R)//区间查询,返回[L,R]的和,i是指从哪个节点开始查询,一般是根节点
{
if( tree[i].l>=L && tree[i].r<=R) return tree[i].sum;//如果这个区间被完全包括在目标区间里面,直接返回这个区间的值
if( tree[i].l>R || tree[i].r<L) return 0;//如果这个区间和目标区间毫不相干,返回0
push_down(i);
int s=0;
if(tree[i*2].r>=L) s+=search(i*2,L,R);//如果这个区间的左儿子和目标区间又交集,那么搜索左儿子
if(tree[i*2+1].l<=R) s+=search(i*2+1,L,R);//如果这个区间的右儿子和目标区间又交集,那么搜索右儿子
return s;
}
inline void add_point(int i,int dis,int k)//单点修改,dis就是你要加的那个点
{
if(tree[i].l == tree[i].r)//如果是叶子节点,那么说明找到了
{
tree[i].sum += k;
return;
}
if(dis <= tree[i*2].r) add_point(i*2, dis, k);//在哪往哪跑
else add_point(i*2+1, dis, k);
tree[i].sum = tree[i*2].sum + tree[i*2+1].sum;//返回更新
return;
}
inline void add_interval(int i,int L,int R,int k)//区间修改
{
if(tree[i].l >= L && tree[i].r <= R)
{
tree[i].sum += k*(tree[i].r - tree[i].l + 1);
tree[i].lz+=k;
return;
}
push_down(i);
if(tree[i*2].r >= L)
add_interval(i*2, L, R, k);
if(tree[i*2+1].l <= R)
add_interval(i*2+1, L, R, k);
tree[i].sum = tree[i*2].sum + tree[i*2+1].sum;
}
inline void ask_point(int p, int x)//单点查询
{
ans += tree[p].sum;
if(tree[p].l == tree[p].r) return;
int mid = tree[p].l + tree[p].r >>1;
if(x <= mid) ask_point(p << 1, x);
else ask_point(p << 1 | 1, x);
}
数学
[模板]除法逆元
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll mod; //宏定义一个mod
//快速幂优化
ll quick_pow(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ans;
}
//逆元函数 公式为 (a/b)%mod=(a*b^(mod-2))%mod
ll inv(ll a,ll b)
{
return (a*quick_pow(b,mod-2))%mod;
}
/***
注意事项:逆元函数的使用,a必须能整除b,并且mod为质数
**/
int main()
{
ll a,b;
while(cin>>a>>b>>mod){
cout<<inv(a,b)<<endl;
}
return 0;
}
[模板]分解质因数
#include <bits/stdc++.h>
using namespace std;
int Fenjie(int n)//返回n的质因数个数
{
int res=0;
for(int i=2;i<=n/i;i++)
{
if(n%i==0)
{
res++;
while(n%i==0) n/=i;
}
}
if(n>1) res++;//没有分解干净,原数也是一个质数
return res;
}
[模板]快速幂
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll FastPow(int a,int n)
{
ll base=a;
ll res=1;
while(n)
{
if(n&1) res=(res*base)%mod;
base=(base*base)%mod;
n>>=1;
}
return res;
}
[模板]组合数取模
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll p = 1e9+7;
//组合数取模模板(p较大时,如p=1e9+7)
ll Pow(ll a,ll b)
{
ll ans=1;
while(b){
if(b&1) ans=(ans*a)%p;
a=(a*a)%p;
b>>=1;
}
return ans;
}
ll C(ll n,ll m)
{
if(m==0) return 1;
if(m>n-m) m=n-m;
ll up=1,down=1;
for(int i=1;i<=m;i++){
up=(up*(n-i+1))%p;
down=(down*i)%p;
}
return up*Pow(down,p-2)%p;
}
/***
目的:输出C(n,m)%mod的值
时间复杂度:O(m)
**/
int main()
{
ll m,n;
while(scanf("%lld%lld",&n,&m)!=EOF){
printf("%lld\n",C(n,m));
}
return 0;
}
STL
[STL]nth_element
#include<bits/stdc++.h>
using namespace std;
bool cmp(int a, int b){
return a > b;
}
//C++的STL库中的nth_element()方法,默认是求区间第k小的(划重点)。
//nth_element(a,a+n-k,a+n),将下标为n-k,也就是第n-k+1个数放在正确的位置,求的是第k大的数a[n-k]。
int main()
{
int a[9] = {4,7,6,9,1,8,2,3,5};
int b[9] = {4,7,6,9,1,8,2,3,5};
int c[9] = {4,7,6,9,1,8,2,3,5};
nth_element(a,a+2,a+9);
//将下标为2,也就是第3个数放在正确的位置
//也就是求的是第3小
cout <<"第3小是:"<< a[2] << endl;
for(int i = 0; i < 9; i++)
cout << a[i] << " "; puts("");//注意下标是从0開始计数的
//那么求第3大,就是求第9-3+1小,即第7小
//也就是将下标为6的第7个数,放在正确的位置
nth_element(b,b+6,b+9);
cout <<"第3大是:"<< b[6] << endl;
for(int i = 0; i < 9; i++)
cout << b[i] << " "; puts("");//注意下标是从0開始计数的
nth_element(c,c+2,c+9,cmp);//第一种方法
//nth_element(c,c+2,c+9,greater<int>()); //第二种方法
cout <<"第3大是:"<< c[2] << endl;
for(int i = 0; i < 9; i++)
cout << c[i] << " "; //注意下标是从0開始计数的
}
图论
[模板]链式前向星
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+7;
struct node//边:终点 to,权值 w,下一天边 next,起点放在 head[] 中
{
int to, next, w;
}edge[maxn];
int head[maxn];//head[u] 指向结点 u 的第一个边的储存位置
int cnt;//记录 edge[] 的末尾位置。新加入的边放在末尾
void init()//初始化
{
for (int i = 0; i < maxn; i++)
{
head[i] = -1;//-1:不存在从结点 i 出发的边
edge[i].next = -1;//-1:结束,没有下一个边
}
cnt = 0;
}
void add_edge(int u,int v,int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];//指向结点 u 上一次存的边的位置
head[u] = cnt++;//更新节点 u 最新边的存放位置:就是 edge 的末尾
}
[模板]邻接表
#include<bits/stdc++.h>
#define endl "\n";
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
struct edge//定义边
{
int from, to, w;
edge(int a, int b, int c) {from=a; to=b; w=c;}
};
vector<edge> e[maxn];
int n;
void initial()//初始化
{
for(int i=1; i<=n; i++)
e[i].clear();
}
void add_edge(int a,int b,int c)//存边
{
e[a].push_back(edge(a,b,c));
}
void ask_edge(int u)//检索结点u的所有邻居
{
for(int i=0; i<e[u].size(); i++)
{
return;//...
}
}
[模板]拓扑排序
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+7;
class BFS_LinJieBiao//一:基于BFS的拓扑排序,用邻接表存储
{
int n,m;//n是有几个结点,m是有几条边
int in[maxn];//记录入度
vector<int> edge[maxn];//边
vector<int> ans;//排序结果
queue<int> q;//队列
void init()
{
for(int i=1; i<=m; i++)
{
int from,to;
cin>>from>>to;
edge[from].push_back(to);
in[to]++;
}
for(int i=1;i<=n;i++)
{
if(in[i]==0)
q.push(i);
}
}
bool topsort()
{
while(!q.empty())
{
int t = q.front();
ans.push_back(t);
q.pop();
for (int i=0; i<edge[t].size(); i++)
{
in[edge[t][i]]--;
if (in[edge[t][i]] == 0)
q.push(edge[t][i]);
}
}
if (ans.size() == n)
{
for(int i=0; i<n; i++)
cout<<ans[i];
return true;
}
else
{
return false;
}
}
};
class BFS_LianShiQianXiangXing//一:基于BFS的拓扑排序,用链式前向星存储,用优先队列实现了输出最小字典序的排序
{
struct node
{
int to,next;
}edge[maxn];
int n,m,cnt;
int head[maxn];
int in[maxn];//入度
vector<int> ans;
priority_queue<int, vector<int>, greater<int> > q;
void init()
{
for(int i=0;i<maxn;i++)
{
head[i]=-1;
in[i]=0;
cnt=0;
}
}
void add(int u,int v)
{
edge[cnt] = node{v, head[u]};
head[u] = cnt++;
in[v]++;
}
bool topsort()
{
for (int i=1; i<=n; i++)
if (in[i] == 0)
q.push(i);
while (!q.empty())
{
int u = q.top();
q.pop();
ans.push_back(u);
for (int i=head[u]; i!=-1; i=edge[i].next)
{
if (--in[edge[i].to==0])
q.push(edge[i].to);
}
}
if(ans.size()==n)
{
for (int i=0; i<n; i++)
{
cout<<ans[i];
}
}
else
{
return false;
}
}
};
[模板]LCA最近公共祖先
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
const int maxn=5e5+7;
const int pows=20;
struct node
{
int t,nex;
}e[maxn*2];
int head[maxn],tot;
int fa[maxn][pows+1];//记录节点i的2^j级父节点
int depth[maxn];
int lg[maxn];
int n,m,s;
inline void compute_log2()//预先算出log_2(i)+1的值,用的时候直接调用就可以了,常数优化
{
for(int i=1; i<=n; i++)
lg[i] = log2(i) + 1;/* lg[i-1] + (1 << lg[i-1] == i); */
}
inline void add(int x,int y)//加入树
{
e[++tot].t = y;
e[tot].nex = head[x];
head[x] = tot;
}
inline void dfs(int now, int fath)//now表示起始节点,fath表示其父节点
{
fa[now][0] = fath; // 初始化:第 2^0 = 1 个祖先就是它的父亲节点,dep 也比父亲节点多 1。
depth[now] = depth[fath] + 1;
for(int i=1; i<=lg[depth[now]]; i++)
{
fa[now][i] = fa[fa[now][i-1]][i-1];//now的2^i祖先等于now的2^(i-1)祖先的2^(i-1)祖先
}
for(int i=head[now]; i; i=e[i].nex)
{
if(e[i].t != fath) dfs(e[i].t, now);
}
}
inline int LCA(int x,int y)//计算 x 和 y 的LCA
{
if(depth[x] < depth[y])//假设x的深度 >= y的深度
swap(x, y);
while(depth[x] > depth[y])
x = fa[x][lg[depth[x]-depth[y]]-1];
if(x == y)//x是y的祖先
return x;
for(int k=lg[depth[x]]-1; k>=0; k--)//向上跳
{
if(fa[x][k] != fa[y][k])//因为我们要跳到它们LCA的下面一层,所以它们肯定不相等,如果不相等就跳过去。
{
x = fa[x][k];
y = fa[y][k];
}
}
return fa[x][0];
}
杂项
[模板]蔡勒公式
#include <iostream>
using namespace std;
int main() {
int year, month, day;
cout << "请用数字输出年、月、日,并使用空格隔开:" << endl;
while (cin >> year >> month >> day) {
if (month < 3) {
year -= 1;
month += 12;
}
char week[7][10] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
int c = int(year / 100), y = year - 100 * c;
int w = int(c / 4) - 2 * c + y + int(y / 4) + (26 * (month + 1) / 10) +
day - 1;
w = (w % 7 + 7) % 7;
cout << week[w] << endl;
}
return 0;
}
[模板]基姆拉尔森计算公式
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int Date(int y,int m,int d)
{
if(m==1||m==2){//一二月换算
m+=12;
y--;
}
int week = (d + 2*m +3*(m+1)/5 + y + y/4 - y/100 + y/400 + 1)%7;
return week;//其中1~7表示周一到周日
}
int main()
{
//0是周日
cout<<Date(2024,1,13);
}
优化
[优化]区间伸缩
#include<bits/stdc++.h>
#define endl "\n"
using namespace std;
typedef long long ll;
const int inf=INT_MAX;
const int mod=1e9+7;
const int maxn=1e6+7;
const int bmax=2e3+7;
int v[maxn];
int b[bmax];
//洛谷P1638 逛画展
void solve()
{
int n,m;
cin>>n>>m;
pair<int,int> p;
for(int i=1;i<=n;i++)
{
cin>>v[i];
}
int i=1,j=1;
int cnt=1;
int ans=inf;
b[v[1]]++;
while(i<=j && j<=n)
{
if(cnt==m)
{
if(ans>j-i+1)
{
ans=j-i+1;
p={i,j};
}
b[v[i]]--;
if(b[v[i]]==0) cnt--;
i++;
}
else
{
j++;
b[v[j]]++;
if(b[v[j]]==1) cnt++;
}
}
cout<<p.first<<" "<<p.second;
}