来自:算法提高课
文章目录
第六章 基础算法
6.1 位运算
6.1.1 90. 64位整数乘法
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL qadd(LL a,LL b,LL p)
{
LL res=0;
while(b)
{
if(b&1) res=(res+a)%p;
a=(a+a)%p;
b>>=1;
}
return res;
}
int main()
{
LL a,b,p;
cin>>a>>b>>p;
cout<<qadd(a,b,p);
return 0;
}
6.2 递推与递归
6.2.1 95. 费解的开关
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=6;
char g[N][N],bg[N][N];
int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
void turn(int x,int y)
{
if(g[x][y]=='0')
g[x][y]='1';
else
g[x][y]='0';
for(int i=0;i<4;i++)
{
int a=x+dx[i],b=y+dy[i];
if(a<0||a>4||b<0||b>4) continue;
if(g[a][b]=='0')
g[a][b]='1';
else
g[a][b]='0';
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
int res=10;
for(int i=0;i<5;i++) cin>>bg[i];
for(int op=0;op<32;op++)
{
int cnt=0;
memcpy(g,bg,sizeof bg);
// 操作第一行的开关
for(int i=0;i<5;i++)
{
if(op>>i&1)
{
turn(0,i);
cnt++;
}
}
// 递推出第1~4行开关的状态
for(int i=0;i<4;i++)
{
for(int j=0;j<5;j++)
{
if(g[i][j]=='0')
{
turn(i+1,j);
cnt++;
}
}
}
// 检查最后一行灯是否全亮
bool success=true;
for(int i=0;i<5;i++)
{
if(g[4][i]=='0')
success=false;
}
if(success&&res>cnt) res=cnt;
}
if(res>6) res=-1;
cout<<res<<endl;
}
return 0;
}
6.2.2 97. 约数之和
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=9901;
int qmi(int a,int k)
{
int res=1;
a%=mod;
while(k)
{
if(k&1) res=res*a%mod;
a=a*a%mod;
k>>=1;
}
return res;
}
int sum(int p,int k)
{
if(k==1) return 1;
if(k%2==0) return (1+qmi(p,k/2))*sum(p,k/2)%mod;
return (sum(p,k-1)+qmi(p,k-1))%mod;
}
int main()
{
int a,b;
cin>>a>>b;
int res=1;
// 对a分解质因数
for(int i=2;i*i<=a;i++)
{
if(a%i==0)
{
int s=0;
while(a%i==0)
{
a/=i,s++;
}
res=res*sum(i,b*s+1)%mod;
}
}
if(a>1) res=res*sum(a,b+1)%mod;
if(a==0) res=0;
cout<<res;
return 0;
}
6.2.3 98. 分形之城
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
struct Point
{
LL x,y;
Point(){}
Point(LL _x,LL _y)
{
x=_x,y=_y;
}
};
Point get(LL n,LL a)
{
if(n==0) return Point(0,0);
LL block=1ll<<n*2-2,len=1ll<<n-1; //1ll是表示long long型的1,而不是一百一十一
Point p=get(n-1,a%block);
LL x=p.x,y=p.y;
int z=a/block;
if(z==0) return Point(y,x);
else if(z==1) return Point(x,y+len);
else if(z==2) return Point(x+len,y+len);
return Point(len*2-1-y,len-1-x);
}
int main()
{
int T;
cin>>T;
while(T--)
{
LL n,a,b;
cin>>n>>a>>b;
Point pa=get(n,a-1);
Point pb=get(n,b-1);
double dx=pa.x-pb.x,dy=pa.y-pb.y;
//小心按照double输出变成科学计数法
LL res=round(sqrt(dx*dx+dy*dy)*10);
cout<<res<<endl;
}
return 0;
}
6.3 前缀和与差分
6.3.1 99. 激光炸弹
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5010;
int n,r;
int g[N][N];
int main()
{
cin>>n>>r;
for(int i=1;i<=n;i++)
{
int x,y,w;
cin>>x>>y>>w;
g[x+1][y+1]+=w;
}
//注意这里是5001是整个前缀和矩阵,而不是n
for(int i=1;i<=5001;i++)
{
for(int j=1;j<=5001;j++)
{
g[i][j]+=g[i][j-1]+g[i-1][j]-g[i-1][j-1];
}
}
int res=-1;
if(r>5001)
cout<<g[5001][5001]<<endl;
else
{
for(int i=1;i+r<=5002;i++)
{
for(int j=1;j+r<=5002;j++)
{
int x1=i,y1=j,x2=i+r-1,y2=j+r-1;
res=max(res,g[x2][y2]-g[x1-1][y2]-g[x2][y1-1]+g[x1-1][y1-1]);
}
}
cout<<res<<endl;
}
return 0;
}
6.3.2 100. 增减序列
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010;
int n;
LL a[N],b[N];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
b[i]=a[i]-a[i-1];
}
LL p=0,q=0;
for(int i=2;i<=n;i++)
{
if(b[i]>0)
p+=b[i];
else if(b[i]<0)
q-=b[i];
}
LL op=0,cnt=0;
op=max(p,q);
cnt=max(p,q)-min(p,q)+1;
cout<<op<<endl;
cout<<cnt<<endl;
return 0;
}
6.4 二分
6.4.1 102. 最佳牛围栏
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,F;
double a[N],s[N];
bool check(double avg)
{
for(int i=1;i<=n;i++)
s[i]=s[i-1]+a[i]-avg;
double mins=0;
for(int k=F;k<=n;k++)
{
mins=min(mins,s[k-F]);
if(s[k]-mins>=0)
return true;
}
return false;
}
int main()
{
cin>>n>>F;
for(int i=1;i<=n;i++)
cin>>a[i];
double l=0,r=2000;
while(r-l>1e-5)
{
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}
cout<<(int)(r*1000)<<endl;
return 0;
}
6.4.2 113. 特殊排序
代码:
// Forward declaration of compare API.
// bool compare(int a, int b);
// return bool means whether a is less than b.
class Solution {
public:
vector<int> specialSort(int N) {
vector<int> res(1,1);
for(int i=2;i<=N;i++)
{
int l=0,r=res.size()-1;
while(l<r)
{
int mid=l+r+1>>1;
if(compare(res[mid],i)) l=mid;
else r=mid-1;
}
res.push_back(i);
for(int j=res.size()-2;j>r;j--)
swap(res[j],res[j+1]);
if(compare(i,res[r]))
swap(res[r],res[r+1]);
}
return res;
}
};
6.5 排序
6.5.1 105. 七夕祭
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=100010;
int n,m,t;
int row[N],col[N],s[N],c[N];
int work(int n,int a[])
{
for(int i=1;i<=n;i++)
s[i]=s[i-1]+a[i];
if(s[n]%n) return -1;
int avg=s[n]/n;
for(int i=1;i<=n;i++)
c[i]=s[i-1]-(i-1)*avg;
sort(c+1,c+n+1);
LL res=0;
for(int i=1;i<=n;i++)
res+=abs(c[i]-c[(n+1)/2]);
return res;
}
int main()
{
cin>>n>>m>>t;
for(int i=0;i<t;i++)
{
int x,y;
cin>>x>>y;
row[x]++,col[y]++;
}
LL r=work(n,row);
LL c=work(m,col);
if(r!=-1&&c!=-1) cout<<"both "<<r+c<<endl;
else if(r!=-1) cout<<"row "<<r<<endl;
else if(c!=-1) cout<<"column "<<c<<endl;
else cout<<"impossible"<<endl;
return 0;
}
6.5.2 106. 动态中位数
代码:
// 对顶堆
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int p,id,m;
int ans[N],cnt;
int main()
{
cin>>p;
while(p--)
{
priority_queue<int> down; //大根堆,放较小数,个数比小根堆多一
priority_queue<int,vector<int>,greater<int> > up; //小根堆,放较大数
cnt=1;
cin>>id>>m;
for(int i=1;i<=m;i++)
{
int x;
cin>>x;
if(down.size()==0||down.top()>=x)
down.push(x);
else up.push(x);
if(up.size()>=down.size()) //调整堆元素数量
{
down.push(up.top());
up.pop();
}
if(up.size()+1<down.size()) //调整堆元素数量
{
up.push(down.top());
down.pop();
}
if(i%2)
ans[cnt++]=down.top();
}
cout<<id<<" "<<cnt-1<<endl;
for(int i=1;i<cnt;i++)
{
if(i%10==0)
cout<<ans[i]<<endl;
else
cout<<ans[i]<<" ";
}
if((cnt-1)%10)
cout<<endl;
}
return 0;
}
/* 二分插入法
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int p,id,m;
vector<int> a;
int ans[N],cnt;
//整数二分,得到第一个小于等于x的下标
int get(int x)
{
int l=0,r=a.size();
while(l<r)
{
int mid=l+r>>1;
if(a[mid]>=x) r=mid;
else l=mid+1;
}
return r;
}
int main()
{
cin>>p;
while(p--)
{
a.clear();
a.push_back(-1e9);
cnt=1;
cin>>id>>m;
for(int i=1;i<=m;i++)
{
int x;
cin>>x;
if(i==1)
a.push_back(x);
else
{
int k=get(x);
a.insert(a.begin()+k,x);
}
if(i%2)
ans[cnt++]=a[(i+1)/2];
}
cout<<id<<" "<<cnt-1<<endl;
for(int i=1;i<cnt;i++)
{
if(i%10==0)
cout<<ans[i]<<endl;
else
cout<<ans[i]<<" ";
}
if((cnt-1)%10)
cout<<endl;
}
return 0;
}
*/
6.5.3 107. 超快速排序
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=500010;
int n;
int a[N],temp[N];
LL merge_sort(int q[],int l,int r)
{
if(l>=r)
return 0;
int mid=l+r>>1;
LL res=merge_sort(q,l,mid)+merge_sort(q,mid+1,r);
int k=0,i=l,j=mid+1;
while(i<=mid&&j<=r)
{
if(q[i]<=q[j])
temp[k++]=q[i++];
else
{
res+=mid-i+1;
temp[k++]=q[j++];
}
}
while(i<=mid)
{
temp[k++]=q[i++];
}
while(j<=r)
{
temp[k++]=q[j++];
}
for(i=l,j=0;i<=r;i++,j++)
{
q[i]=temp[j];
}
return res;
}
int main()
{
while(true)
{
cin>>n;
if(n==0) break;
for(int i=0;i<n;i++)
cin>>a[i];
cout<<merge_sort(a,0,n-1)<<endl;
}
return 0;
}
6.6 RMQ
6.6.1 1273. 天才的记忆
代码:
// RMQ解法
#include<bits/stdc++.h>
using namespace std;
const int N=200010,M=18;
int n,m;
int w[N];
int f[N][M];
void init()
{
for(int j=0;j<M;j++)
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
if(!j) f[i][j]=w[i];
else f[i][j]=max(f[i][j-1],f[i+(1<<j-1)][j-1]);
}
}
}
int query(int l,int r)
{
int len=r-l+1;
int k=log(len)/log(2);
return max(f[l][k],f[r-(1<<k)+1][k]);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>w[i];
init();
cin>>m;
while(m--)
{
int l,r;
cin>>l>>r;
cout<<query(l,r)<<endl;
}
return 0;
}
/*线段树解法 注意INF取值
#include<bits/stdc++.h>
using namespace std;
const int N=200010,INF=0x3f3f3f3f;
int n,m;
int w[N];
struct Node
{
int l,r;
int v; // 区间[l, r]中的最大值
Node(){}
Node(int _l,int _r,int _v)
{
l=_l,r=_r,v=_v;
}
}tr[4*N];
void pushup(int u) // 由子节点的信息,来计算父节点的信息 u表示父节点编号
{
tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v);
}
void build(int u,int l,int r) //u表示父节点编号,从u开始建立[l,r]的线段树
{
tr[u]=Node(l,r,w[r]);
if(l==r) return;
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r) return tr[u].v; // 树中节点,已经被完全包含在[l, r]中了
int mid=tr[u].l+tr[u].r>>1;
//注意初值
int v=-INF;
if(l<=mid) v=query(u<<1,l,r);
if(r>mid) v=max(v,query(u<<1|1,l,r));
return v;
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>w[i];
build(1,1,n);
cin>>m;
while(m--)
{
int a,b;
cin>>a>>b;
cout<<query(1,a,b)<<endl;
}
return 0;
}
*/