基础算法
枚举
例一:判断一到n中有多少是n的倍数
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
int n;
cin>>n;
int tot=0;
for(int i=1;i<=n;i++){
if(i%3==0){
tot++;
}
}
cout<<tot<<endl;
return 0;
}
例一expexp
l-r中有几个是三的倍数
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int l,r;
cin>>l>>r;
cout<<r/3-(l-1)/3<<endl;
return 0;
}
例一expexpexp
l-r中有多少是3或5或7的倍数
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int l,r;
cin>>l>>r;
int lans,rans;
lans=(l-1)/3+(l-1)/5+(l-1)/7-(l-1)/15-(l-1)/21-(l-1)/35+(l-1)/105;
rans=r/3+r/5+r/7-r/15-r/21-r/35+r/105;
cout<<rans-lans<<endl;
return 0;
}
例二
在一个笼子里有若干只鸡和若干只兔子,其中脚有x只,头有y个,问鸡和兔子各有几只
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iomanip>
using namespace std;
int main(){
int x,y;
cin>>x>>y;
int a,b;
for(int i=0;i<=y;i++)
{
a=i;
b=y-i;
if(a*2+b*4==x){
cout<<a<<" "<<b<<endl;
}
}
return 0;
}
例二exp
在一个笼子里有若干只鸡和若干只兔子,其中脚有x只,头有y个,问鸡和兔子各有几只。其中还存在若干只鸡单脚站立,问可能的方案总数
#include<iostream>
#include<cstdio>
using namespace std;
int x,y;
int a,b,c;
int ans=0;
int main(){
cin>>x>>y;
for(a=0;a<=y;a++)
for(b=0;b<=y;b++){
c=y-a-b;
if(a*2+b*4+c==x){
ans++;
}
}
cout<<ans<<endl;
return 0;
}
例三
你有一百块钱,一只公鸡5块钱,一只母鸡3块钱,三只小鸡一块钱,
百钱买百鸡,输出所有可能
#include<iostream>
#include<cstdio>
using namespace std;
int main(){
int ans=0;
int a,b,c;
for(a=0;a<=100;a++){
for(b=0;b<=100;b++){
c=100-a-b;
if(c>=0&&a*5+b*3+(c+2)/3==100&&a+b+c==100){
cout<<a<<" "<<b<<" "<<c<<endl;
ans++;
}
}
}
return 0;
}
例四
质数判断
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main(){
int n;
cin>>n;
bool a=1;
for(int i=2;i<=int(sqrt(n));i++){
if(n%i==0) a=false;
}
if(a){
cout<<"yes"<<endl;
}
else
cout<<"no"<<endl;
return 0;
}
洛谷 P2038 无线网络发射器选址
#include<iostream>
#include<cstdio>
#include<cstring>
#include<iomanip>
#include<cstring>
#include<algorithm>
using namespace std;
int main(){
int d,n;
cin>>d>>n;
int x,y,k;
int a[150][150]={0};
for(int i=1;i<=n;i++){
cin>>x>>y>>k;
a[x][y]=k;
}
int x1,x2,y1,y2;
int l,r;
int tot=0,ans=0,cnt=0;
for(int i=0;i<=128;i++){
for(int j=0;j<=128;j++){
if(i-d<0)
x1=0;
else
x1=i-d;
if(j-d<0)
y1=0;
else
y1=j-d;
if(i+d>128)
x2=128;
else
x2=i+d;
if(j+d>128)
y2=128;
else
y2=j+d;
for(int l=x1;l<=x2;l++){
for(int r=y1;r<=y2;r++){
tot=tot+a[l][r];
}
}
if(tot>ans)
{
ans=tot;
cnt=1;
}
else if(tot==ans){
cnt++;
}
tot=0;
}
}
cout<<cnt<<" "<<ans<<endl;
return 0;
}
火柴棒等式
给你n根火柴棍,你可以拼出多少个形如“A+B=C”的等式?等式中的A、B、C是用火柴棍拼出的整数(若该数非零,则最高位不能是0)。用火柴棍拼数字0-9的拼法如图所示:
注意:
- 加号与等号各自需要两根火柴棍
- 如果A≠B,则A+B=C与B+A=C视为不同的等式(A、B、C>=0)
- n根火柴棍必须全部用上
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int f[100001];
f[0]=6;
f[1]=2;
f[2]=5;
f[3]=5;
f[4]=4;
f[5]=5;
f[6]=6;
f[7]=3;
f[8]=7;
f[9]=6;
int n;
cin>>n;
for(int i=10;i<=19999;i++)
{
f[i]=f[i/10]+f[i%10];
}
int sum=0;
for(int a=0;a<=9999;a++)
for(int b=0;b<=9999;b++)
{
int c=a+b;
if(f[a]+2+f[b]+2+f[c]==n) sum++;
}
cout<<sum<<endl;
return 0;
}
十进制分解
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n;
cin>>n;
int cnt[10000];
int i=0;
while(n>0)
{
cnt[i++]=n%10;
n=n/10;
}
for(int j=i-1;j>=0;j--)
{
cout<<cnt[j]<<" ";
}
return 0;
/*string s;
getline(cin,s);
for(int i=0;i<s.size();i++)
{
cout<<s[i]<<" ";
}
cout<<endl;
return 0;*/
}
simple problem
给定n个数ai及m个询问。
每次询问一段区间的和。
O(n+m)
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a[n+5];
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int f[n+5];
f[0]=0;
for(int i=1;i<=n;i++)
{
f[i]=f[i-1]+a[i];
}
int A,B;
for(int i=1;i<=m;i++)
{
cin>>A>>B;
cout<<f[B]-f[A-1]<<endl;
}
return 0;
}
simple problem exp
给定一个nn的矩阵及m个询问,每次询问一个子矩阵的和
O(nn+m)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a[10000][10000];
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a[i][j];
}
int f[100000];
f[0][0]=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
f[i][j]=f[i][j-1]+f[i-1][j]-f[i-1][j-1]+a[i][j];
}
}
for(int i=1;i<=m;i++){
cin>>x>>y>>p>>q;
cout<<f[p][q]-f[x-1][q]-f[p][y-1]+f[x-1][y-1]<<endl;
}
return 0;
}
最大子矩阵
n^6
#include<iostream>
#include<cstdio>
using namespace std;
int main()
{
int a[100][100];
int n;
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
{
cin>>a[i][j];
}
int sum=0;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
for(int l=i;l<n;l++)
for(int r=j;r<n;r++)
for(int m=i;m<l;m++)
for(int n=j;n<r;n++)
{
sum+=a[m][j];
}
cout<<sum<<endl;
return 0;
}
1*n的矩阵的最大子矩阵
(洛谷 P1115 最大字段和)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
using namespace std;
int a[200005],f[200005],g[200005];
int main(){
int n;
cin>>n;
f[0]=0;
for(int i=1;i<=n;i++){
cin>>a[i];
f[i]=f[i-1]+a[i];
}
g[1]=a[1];
int minn=min(0,f[1]);
for(int i=2;i<=n;i++){
g[i]=f[i]-minn;
minn=min(minn,f[i]);
}
int ans=-11111;
for(int i=1;i<=n;i++){
ans=max(ans,g[i]);
}
cout<<ans<<endl;
return 0;
}
圈地运动
n^3(未检验)
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
using namespace std;
int main()
{
int n;
cin>>n;
int a[n+5][n+5]; //存数组
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
int g[n+5][n+5]; //求第j列中第一行到第n行的和
int tot=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
tot=a[j][i]+tot;
g[j][i]=tot;
}
}
/*
int f[1000][1000]; //存数组的前缀和
f[0][0]=0;
int sum=0;
for(int i;i<=n;i++)
for(int j=1;j<=n;j++){
for(int m=i;m>=1;m--)
for(int n=j;n>=1;n--){
sum=sum+a[i][j];
}
f[i][j]=sum;
}
*/
int b[1000]; //求最大矩阵和
int MIN[10000];
int f[1000000];
f[0]=0;
int ans=-10000;
for(int d=1;d<=n;d++)
for(int u=d;u<=n;u++){
for(int i=1;i<=n;i++) b[i]=g[u][i]-g[d-1][i];
for(int j=1;j<=n;j++) f[j]=f[j-1]+b[j];
MIN[0]=-10000;
for(int k=1;k<=n;k++) MIN[k]=min(MIN[k-1],f[k]);
for(int l=1;l<=n;l++) ans=max(ans,f[l]-MIN[l-1]);
}
cout<<ans<<endl;
return 0;
}
对手圈地运动
给定一个n*n的矩阵,你的对手在找一个最大子矩阵,并且他知道n^3的做法。
你可以改变其中至多一个数字变成k,让你的对手找到的最大子矩阵尽可能小
(不会)
洛谷 P1058 立体图
#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
using namespace std;
const int n=10000;
char ans[n][n];
int a[n][n];
void drw(int x,int y){
//zm
ans[x][y]=ans[x+4][y]=ans[x][y+3]=ans[x+4][y+3]='+';
for(int i=x+1;i<x+4;i++){
ans[i][y]='-';
ans[i][y+3]='-';
}
for(int i=y+1;i<y+3;i++){
ans[x][i]='|';
ans[x+4][i]='|';
}
for(int i=y+1;i<y+3;i++){
for(int j=x+1;j<x+4;j++){
ans[j][i]=' ';
}
}
//right
ans[x+5][y+1]='/';
ans[x+5][y+2]=ans[x+5][y+3]=' ';
ans[x+6][y+2]='+';
ans[x+6][y+3]=ans[x+6][y+4]='|';
//up
ans[x+1][y+4]=ans[x+5][y+4]='/';
for(int i=x+2;i<=x+4;i++){
ans[i][y+4]=' ';
}
ans[x+2][y+5]=ans[x+6][y+5]='+';
for(int i=x+3;i<=x+5;i++){
ans[i][y+5]='-';
}
}
void cinout(int x,int y){
for(int i=y;i>=0;i--){
for(int j=0;j<=x;j++){
if(!ans[j][i]){
putchar('.');
}
else putchar(ans[j][i]);
}
cout<<endl;
}
}
int main(){
int m,n;
cin>>m>>n;
for(int i=m-1;i>=0;i--){
for(int j=0;j<n;j++){
cin>>a[j][i];
}
}
int mx=0,my=0;
for(int y=m-1;y>=0;y--){
for(int x=0;x<n;x++){
for(int z=0;z<=a[x][y]-1;z++){
mx=max(mx,2*y+4*x+6);
my=max(my,2*y+3*z+5);
drw(2*y+4*x,2*y+3*z);
}
}
}
cinout(mx,my);
return 0;
}
二分大法
有n个数ai,有m次询问,每次询问一个数在这n个数中排第几
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main()
{
int n,m;
cin>>n>>m;
int a[n+5];
for(int i=0;i<n;i++)
{
cin>>a[i];
}
sort(a,a+n);
int l,r;
int mid=(a[0]+a[n-1])/2;
for(int i=0;i<m;i++)
{
cin>>k;
while(l<=r)
{
if(a[mid]==k) return mid;
else if(k>mid)
{
l=mid+1;
}
else r=mid-1;
mid=(l+r)/2;
}
}
cout<<mid<<endl;
return 0;
}
搜索
有n件物品,每件物品可选可不选,枚举所有方案。
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
int sum=0;
int a[1000000];
int n;
using namespace std;
void dfs(int x){
if(x==n+1){
sum++;
return ;
}
a[x]=1;
dfs(x+1);
a[x]=0;
dfs(x+1);
}
}
int main(){
cin >> n;
dfs(1);
cout<<sum<<endl;
return 0;
}
k‘th number
有n个数,共2^n个子集,一个子集的值看做其所有数的和,求第k大的子集。n<=40
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int ans[10000];
int tot=0;
int n,k;
int a[100005];
void dfs(int x,int y){
if(x==n+1) {
tot++;
ans[tot]=y;
return;
}
dfs(x+1,y+a[x]);
dfs(x+1,y);
}
int main(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
dfs(1,0);
sort(ans+1,ans+1+n);
cout<<ans[k];
return 0;
}
0/1背包问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,m;
int ans;
int w[100000],v[100000];
void dfs(int x,int y,int z){
if(x==n+1){
if(y<=m){
ans=max(ans,z);
return;
}
}
for(int i=1;i<=(m-y)/w[x];i++){
dfs(x+1,y+w[i]*i,z+v[i]*i);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>w[i]>>v[i];
}
dfs(1,0,0);
cout<<ans<<endl;
}
0/1背包问题优化
0/1/2背包问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,m;
int ans;
int w[100000],v[100000];
void dfs(int x,int y,int z){
if(x==n+1){
if(y<=m){
ans=max(ans,z);
return;
}
}
for(int i=1;i<=2;i++){
dfs(x+1,y+w[i]*i,z+v[i]*i);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>w[i]>>v[i];
}
dfs(1,0,0);
cout<<ans<<endl;
}
0/1/2/3/…背包问题
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<iomanip>
#include<algorithm>
using namespace std;
int n,m;
int ans;
int w[100000],v[100000],k[1000000];
void dfs(int x,int y,int z){
if(x==n+1){
if(y<=m){
ans=max(ans,z);
return;
}
}
for(int i=1;i<=k[x];i++){
dfs(x+1,y+w[i]*i,z+v[i]*i);
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>w[i]>>v[i]>>k[i];
}
dfs(1,0,0);
cout<<ans<<endl;
}
快速幂
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<iomanip>
#include<algorithm>
using namespace std;
int f[10000];
int c[10000];
int cnt=1;
int ans=1;
int ksm(int x,int y,int z){
if(y==0) return 0;
while(y){
if(y%2==1){
ans=ans*x%z;
}
x=x*x%z;
y=y/2;
}
return ans;
}
int main(){
int a,b,p;
cin>>a>>b>>p;
ksm(a,b);
f[0]=a;
int c=1;
for(int i=1;i<=b;i++){
c=c*a;
}
cout<<c%p<<" "<<ans%p<<endl;
return 0;
}
洛谷 P1965 转圈游戏
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int ans=1;
int ksm(int x,int y,int z){
if(y==0) return 0;
while(y){
if(y%2==1){
ans=ans*x%z;
}
x=x*x%z;
y=y/2;
}
return ans;
}
int main(){
int n,m,k,x;
cin>>n>>m>>k>>x;
cout<<(x+ksm(10,k,n)*m)%n<<endl;
return 0;
}
洛谷 P1880 石子合并
dp
洛谷 P1123 取数游戏
#include<iostream>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<algorithm>
using namespace std;
int ans=0;
int u[1000][10000]={0};
int n,m;
int f[1000][1000];
void dfs(int a,int b,int c){
if(a>n){
ans=max(ans,c);
return ;
}
int nxta=a,nxtb=b+1;
if(nxtb>m){
nxtb=1;
nxta=a+1;
}
if(!u[a+1][b+1]&&!u[a+1][b]&&!u[a][b+1]&&!u[a-1][b+1]&&!u[a+1][b-1]&&!u[a-1][b]&&!u[a][b-1]&&!u[a-1][b-1]){
u[a][b]=1;
dfs(nxta,nxtb,c+f[a][b]);
u[a][b]=0;
}
dfs(nxta,nxtb,c);
}
int main(){
int t;
cin>>t;
for(int i=1;i<=t;i++){
cin>>n>>m;
for(int j=1;j<=n;j++)
for(int k=1;k<=m;k++){
cin>>f[j][k];
}
dfs(1,1,0);
cout<<ans<<endl;
ans=0;
}
return 0;
}
取区间游戏
有n个区间,第i个区间形如【li,ri】
要求选择最多的区间,使任意两个区间都互相不重叠
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
using namespace std;
struct qj{
int l;
int r;
}a[200001];
int cmp(const qj &s1,const qj &s2){
return s1.r<s2.r;
}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i].l>>a[i].r;
}
sort(a+1,a+1+n,cmp);
int ans=-111;
int tot=0;
for(int i=1;i<=n;i++){
if(a[i].l>ans){
ans=a[i].r;
tot++;
}
}
cout<<tot<<endl;
return 0;
}
洛谷 P1650 田忌赛马
特殊的二分图最佳匹配