国赛死亡冲刺
二分
模板:
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while (l < r)
{
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
return l;
}
浮点数二分算法模板
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
例题:
789. 数的范围
https://www.acwing.com/problem/content/791/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5+5;
int n,q;
int a[N];
//不小于
int fun1(int x){
int l=0;
int r=n-1;
while(l<r){
int mid=(l+r)>>1;
if(a[mid]<x){
l=mid+1;
}
else r=mid;
}
if(a[l]!=x) return -1;
else return l;
}
//不大于
int fun2(int x){
int l=0;
int r=n-1;
while(l<r){
int mid=(l+r+1)>>1;
if(a[mid]>x) r=mid-1;
else l=mid;
}
if(a[l]!=x) return -1;
else return l;
}
int main()
{
cin>>n>>q;
for (int i = 0; i < n; i ++ ){
cin>>a[i];
}
while(q--){
int k;
cin>>k;
cout<<fun1(k)<<" "<<fun2(k)<<endl;
}
return 0;
}
前缀和与差分
前缀和
二维前缀和
796. 子矩阵的和
https://www.acwing.com/problem/content/798/
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e3+5;
int s[N][N];//s[i][j]该点左上角的矩阵前缀和
int n,m,q;
int get_prefix_sum(int x1,int y1,int x2,int y2){
return s[x2][y2]-s[x1-1][y2]-s[x2][y1-1]+s[x1-1][y1-1];
}
int main()
{
cin>>n>>m>>q;
for (int i = 1; i <= n; i ++ ){
for(int j = 1;j <= m;j ++){
cin>>s[i][j];
s[i][j]+=s[i-1][j]+s[i][j-1]-s[i-1][j-1];
}
}
while(q--){
int x1,y1,x2,y2;
cin>>x1>>y1>>x2>>y2;
cout<<get_prefix_sum(x1,y1,x2,y2)<<endl;
}
return 0;
}
差分
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int a[N];
int n,m;
void insert(int l,int r,int x){
a[l]+=x;
a[r+1]-=x;
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int x;
cin>>x;
insert(i,i,x);
}
while(m--){
int l,r,c;
cin>>l>>r>>c;
insert(l,r,c);
}
for(int i=1;i<=n;i++){
a[i]+=a[i-1];
cout<<a[i]<<" ";
}
puts("");
return 0;
}
// freopen("testdata.in", "r", stdin);
二维差分
798. 差分矩阵
https://www.acwing.com/problem/content/800/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1005;
int a[N][N];//前缀和是以左上角看 差分就以右下角看
int n,m,q;
void insert(int x1,int y1,int x2,int y2,int x){
a[x1][y1]+=x;
a[x2+1][y1]-=x;
a[x1][y2+1]-=x;
a[x2+1][y2+1]+=x;
}
int main(){
cin>>n>>m>>q;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x;
cin>>x;
insert(i,j,i,j,x);
}
}
while(q--){
int x1,y1,x2,y2,c;
cin>>x1>>y1>>x2>>y2>>c;
insert(x1,y1,x2,y2,c);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
cout<<a[i][j]<<" ";
}
puts("");
}
return 0;
}
// freopen("testdata.in", "r", stdin);
并查集
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int p[N];
int n,m;
int find(int x){
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++) p[i]=i;
while(m--){
char c;
int a,b;
cin>>c>>a>>b;
int x=find(a);
int y=find(b);
if(c=='M'){
if(x!=y) p[x]=y;
}
else if(x==y) puts("Yes");
else puts("No");
}
return 0;
}
// freopen("testdata.in", "r", stdin);
trie
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int N=1e5+5;
char c[N];
int son[N][26],cnt[N],idx;
char str[N];
void insert(char *str){
int p=0;
for(int i=0;str[i];i++){
int u=str[i]-'a';
if(!son[p][u]) son[p][u]=++idx;
p=son[p][u];
}
cnt[p]++;//以该字符结尾计数
}
int query(char * str){
int p=0;
for(int i=0;str[i];i++){
int u=str[i]-'a';
if(!son[p][u]) return 0;
p=son[p][u];
}
return cnt[p];
}
int main()
{
int n;
scanf("%d", &n);
while (n -- )
{
char op[2];
scanf("%s%s", op, str);
if (*op == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
// freopen("testdata.in", "r", stdin);
单调队列
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e6+5;
int n,k;
int a[N],q1[N],q2[N];
void min_queue(){
int hh=0,tt=-1;
for(int i=0;i<n;i++){
//判断队头是否已经弹出
if(hh<=tt && i-k+1>q1[hh]) hh++;
//删除所有比当前值小的数
while(hh<=tt && a[i]<=a[q1[tt]]) tt--;
q1[++tt]=i;
if(i>=k-1) printf("%d ",a[q1[hh]]);
}
puts("");
}
void max_queue(){
int hh=0,tt=-1;
for(int i=0;i<n;i++){
//判断队头是否已经弹出
if(hh<=tt && i-k+1>q2[hh]) hh++;
//删除所有比当前值小的数
while(hh<=tt && a[i]>=a[q2[tt]]) tt--;
q2[++tt]=i;
if(i>=k-1) printf("%d ",a[q2[hh]]);
}
puts("");
}
int main(){
cin>>n>>k;
for(int i=0;i<n;i++) scanf("%d",a+i);
min_queue();
max_queue();
return 0;
}
// freopen("testdata.in", "r", stdin);
双指针
- 最长连续不重复子序列
https://www.acwing.com/problem/content/801/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int a[N];
int st[N];
int n;
int main(){
cin>>n;
for(int i=0;i<n;i++) cin>>a[i];
int res=0;
for(int i=0,j=0;i<n;i++){
st[a[i]]++;
while(st[a[i]]>1 && j<i){
st[a[j]]--;
j++;
}
res=max(res,i-j+1);
}
cout<<res<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
图论
spfa
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef pair<int,int>PII;
const int N=1e6+5;
int h[N],e[N],w[N],ne[N],idx;
int dist[N];
bool st[N];//标记当前队列有哪些元素
int n,m;
void add(int a,int b,int c){
e[idx]=b;
w[idx]=c;
ne[idx]=h[a];
h[a]=idx++;
}
void fun(){
memset(dist,0x3f,sizeof dist);
dist[1]=0;
st[1]=true;
queue<int >q;
q.push(1);
while(q.size()){
int k=q.front();
st[k]=false;
q.pop();
for(int i=h[k];i!=-1;i=ne[i]){
int j=e[i];
if(dist[j]>dist[k]+w[i]){
dist[j]=dist[k]+w[i];
if(!st[j]){//队列中没有j
q.push(j);
st[j]=true;
}
}
}
}
}
int main(){
cin>>n>>m;
memset(h,-1,sizeof h);
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
}
fun();
if (dist[n] > 0x3f3f3f3f / 2) puts("impossible");
else cout<<dist[n]<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
最小生成树
- Kruskal算法求最小生成树
https://www.acwing.com/problem/content/861/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N=1e5+10,M=2e5+10,INF=0x3f3f3f3f;
int n,m;
int p[N];
struct Edge{
int a,b,c;
}edge[M];
bool cmp(Edge x,Edge y){
return x.c<y.c;
}
int find(int x){
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal(){
for(int i=1;i<=n;i++) p[i]=i;
int res=0,cnt=0;
for(int i=1;i<=m;i++){
int a=edge[i].a;
int b=edge[i].b;
int c=edge[i].c;
a=find(a);
b=find(b);
if(a!=b){
res+=c;
p[a]=b;
cnt++;
}
}
if(cnt<n-1) return INF;
else return res;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int a,b,c;
cin>>a>>b>>c;
edge[i]={a,b,c};
}
sort(edge+1,edge+1+m,cmp);
int t=kruskal();
if (t==INF) puts("impossible");
else printf("%d\n",t);
return 0;
}
// freopen("testdata.in", "r", stdin);
各种容器
unorder_map
简单例子
unordered_map<string,int>m;
m["s"]=54;
cout<<m.count("s")<<endl;
cout<<m["s"]<<endl;
priority_queue
小根堆优先队列定义方法
priority_queue<int,vector<int>,greater<int> >q;
string
https://www.cnblogs.com/OfflineBoy/p/13658526.html
数论
867. 分解质因数
https://www.acwing.com/problem/content/869/
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
void fun(int x){
for(int i=2;i<=x/i;i++){
if(x%i==0){
int s=0;
while(x%i==0){
s++;
x/=i;
}
cout<<i<<' '<<s<<endl;
}
}
if (x>1) cout<< x <<' '<<1<<endl;
cout<<endl;
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
fun(x);
}
return 0;
}
// freopen("testdata.in", "r", stdin);
869. 试除法求约数
https://www.acwing.com/problem/content/871/
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
vector<int> fun(int n){
vector<int> res;
for(int i=1;i<=n/i;i++){
if(n%i==0){
res.push_back(i);
//如果n能整除i,那么也能整除n/i
if(i!=n/i){
res.push_back(n/i);
}
}
}
sort(res.begin(),res.end());
return res;
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
auto res=fun(x);
for(auto i:res){
cout<<i<<" ";
}
cout<<endl;
}
return 0;
}
// freopen("testdata.in", "r", stdin);
870. 约数个数
https://www.acwing.com/problem/content/872/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
int n;
int main(){
cin>>n;
unordered_map<int,int>primes;
LL ans=1;
while(n--){
int x;
cin>>x;
for(int i=2;i<=x/i;i++){
while(x%i==0){
x/=i;
primes[i]++;
}
}
if(x>1) primes[x]++;
}
for(auto prime:primes){
ans=ans*(prime.second+1)%mod;
}
cout<<ans<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
871. 约数之和
https://www.acwing.com/problem/content/873/
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int mod=1e9+7;
int main(){
int n;
cin>>n;
unordered_map<int,int>primes;
while(n--){
int x;
cin>>x;
for(int i=2;i<=x/i;i++){
while(x%i==0){
x/=i;
primes[i]++;
}
}
if (x>1) primes[x] ++ ;
}
LL res=1;
for(auto prime: primes){
int p=prime.first,a=prime.second;
LL t=1;;
while(a--){
t=(t*p+1)%mod;
//t=1时 乘一次就是p+1 乘两次就是p平方+p+1
}
res=res*t%mod;
}
cout<<res<<endl;
return 0;
}
// freopen("testdata.in", "r", stdin);
873. 欧拉函数
https://www.acwing.com/video/298/

#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
int fun(int x){
int res=x;
for(int i=2;i<=x/i;i++){
if(x%i==0){
res=res/i*(i-1);//先除后乘 避免数据溢出
while(x%i==0) x/=i;
}
}
if(x>1) res=res/x*(x-1);
return res;
}
int main(){
int n;
cin>>n;
while(n--){
int a;
scanf("%d",&a);
cout<<fun(a)<<endl;
}
return 0;
}
// freopen("testdata.in", "r", stdin);
线性筛法
#include<cstdio>
#include<iostream>
using namespace std;
int check[100000001];
int prime[1000001];
int main()
{
int n,q;
int cnt=0;
//根据n<=10^8,q<=10^6开对应的数组大小,防止MLE
//初始将check数组全部标记为0,标0的是素数,标1的不是素数
scanf("%d%d",&n,&q);
check[1]=1;//1不是素数
for(int i=2;i<=n;i++)
{
if(!check[i])prime[cnt++]=i;//若当前数i没有被之前的所有数筛掉,表明i是素数,将i添加进素数表prime
for(int j=0;j<cnt&&i*prime[j]<100000001;j++)//注意i*prime[j]不要超过n的上限(10^8)
{
check[i*prime[j]]=1;//将当前素数prime[j]的i倍标记为合数
if(i%prime[j]==0)break;//关键步骤:保证每个合数只被筛一次
}
}
for(int i=1;i<=q;i++)
{
scanf("%d",&n);
printf("%d\n",prime[n-1]);//由于素数表从0开始存,所以输出时下标应减1
}
return 0;
}
int string 互相转换
废物机房用不了to_string
用sstream
#include<sstream>
void i2s(int i,string &str){//str记得是引用
stringstream ss;
ss<<i;
ss>>str;
}
字符串转数字 同理反过来写即可
void fun(int &x,string str){
stringstream ss;
ss<<str;
ss>>x;
}
树状数组
https://www.cnblogs.com/OfflineBoy/p/13520110.html
devc开启C++11
-std=c++11

浙公网安备 33010602011771号