“蓝桥杯”练习系统试题集,题解答案(C/C++)_蓝桥杯算法训练答案-程序员宅基地

技术标签: 软件编程  题解集合  蓝桥杯  算法设计  程序设计  解题报告  

文章目录


将定期更新蓝桥杯习题集的解题报告~

二、基础练习

BASIC-1 闰年判断

#include<bits/stdc++.h>
using namespace std;
bool f(int x){
    
    if(x%4==0&&x%100!=0)return 1;
    if(x%400==0)return 1;
    return 0;
}
int main(){
    
    int n;
    while(scanf("%d",&n)!=EOF){
    
        if(f(n))printf("yes\n");
        else printf("no\n");
    }
    return 0;
}

BASIC-2 01字串

#include<bits/stdc++.h>
using namespace std;

int main(){
    
    for(int i=0;i<(1<<5);i++){
    
        int x=i;
        for(int j=4;j>=0;j--){
    
            printf("%d",(x>>j)&1);
        }
        printf("\n");
    }
    return 0;
}

BASIC-3 字母图形

#include<bits/stdc++.h>
using namespace std;

int main(){
    
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;i++){
    
        for(int j=0;j<m;j++){
    
            printf("%c",'A'+abs(i-j));
        }
        printf("\n");
    }
    return 0;
}

BASIC-4 数列特征

#include<bits/stdc++.h>
using namespace std;
#define maxn 100052
int a[maxn];
int main(){
    
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        scanf("%d",&a[i]);
    }
    int ans1=-maxn,ans2=maxn,ans=0;
    for(int i=0;i<n;i++){
    
        ans1=max(ans1,a[i]);
        ans2=min(ans2,a[i]);
        ans+=a[i];
    }
    printf("%d\n%d\n%d\n",ans1,ans2,ans);
    return 0;
}

BASIC-5 查找整数

#include<bits/stdc++.h>
using namespace std;
#define maxn 100052
int a[maxn];
int main(){
    
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        scanf("%d",&a[i]);
    }
    int x;
    scanf("%d",&x);
    //int ans1=-maxn,ans2=maxn,ans=0;
    for(int i=0;i<n;i++){
    
        if(a[i]==x){
    
            printf("%d",i+1);
            return 0;
        }
    }
    printf("-1");
    //printf("%d\n%d\n%d\n",ans1,ans2,ans);
    return 0;
}

BASIC-6 杨辉三角形

#include<bits/stdc++.h>
using namespace std;
#define maxn 100
typedef long long int qq;
qq dp[maxn][maxn];
qq c(int n,int m){
    
    if(n==m||m==0)return 1;
    if(dp[n][m]!=-1)return dp[n][m];
    return dp[n][m]=c(n-1,m-1)+c(n-1,m);
}
int main(){
    
    memset(dp,-1,sizeof(dp));
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        for(int j=0;j<=i;j++){
    
            if(j!=0)printf(" ");
            printf("%lld",c(i,j));
        }
        printf("\n");
    }
    return 0;
}

BASIC-7 特殊的数字

#include<bits/stdc++.h>
using namespace std;
#define p3(x) ((x)*(x)*(x))
int f(int x){
    
    int a[10],cnt=0;
    int ret=0;
    while(x>0){
    
        a[cnt++]=x%10;
        ret+=p3(a[cnt-1]);
        x/=10;
    }
    return ret;
}
int main(){
    
    //while(scanf("%d",&n)!=EOF){
    
        for(int i=100;i<1000;i++){
    
            if(f(i)==i)printf("%d\n",i);
        }
    //}
    return 0;
}

BASIC-8 回文数

#include<bits/stdc++.h>
using namespace std;
int n;
bool f(int x){
    
    int a[100],cnt=0;
    int ret=0;
    while(x>0){
    
        a[cnt++]=x%10;
        ret+=a[cnt-1];
        x/=10;
    }
    //if(ret!=n)return 0;
    for(int i=0;i<cnt/2;i++){
    
        if(a[i]!=a[cnt-1-i])return 0;
    }
    return 1;
}
int main(){
    
    //while(scanf("%d",&n)!=EOF){
    
        for(int i=1000;i<10000;i++){
    
            if(f(i))printf("%d\n",i);
        }
    //}
    return 0;
}

BASIC-9 特殊回文数

#include<bits/stdc++.h>
using namespace std;
int n;
bool f(int x){
    
    int a[100],cnt=0;
    int ret=0;
    while(x>0){
    
        a[cnt++]=x%10;
        ret+=a[cnt-1];
        x/=10;
    }
    if(ret!=n)return 0;
    for(int i=0;i<cnt/2;i++){
    
        if(a[i]!=a[cnt-1-i])return 0;
    }
    return 1;
}
int main(){
    
    while(scanf("%d",&n)!=EOF){
    
        for(int i=10000;i<1000000;i++){
    
            if(f(i))printf("%d\n",i);
        }
    }
    return 0;
}

BASIC-10 十进制转十六进制

#include<bits/stdc++.h>
using namespace std;
const int bas = 16;
char f(int x){
    
    if(x>=10)return x+'A'-10;
    else return x+'0';
}
char a[100];
int main(){
    
    long long int n;
    scanf("%lld",&n);
    if(n==0){
    
        printf("0\n");return 0;
    }
    int cnt=0;
    while(n>0){
    
        a[cnt++]+=f(n%bas);
        n/=bas;
    }
    for(int i=cnt-1;i>=0;i--){
    
        printf("%c",a[i]);
    }
    return 0;
}

BASIC-11 十六进制转十进制

#include<bits/stdc++.h>
using namespace std;
#define maxn 100052
char a[maxn];
bool c[maxn*4]={
    0};
int ans[maxn*2];
int f(char x){
    
    if(x>='A'&&x<='F')return x-'A'+10;
    else return x-'0';
}
int main(){
    
    int T;
    //scanf("%d",&T);
    //while(T--){
    
        scanf("%s",a);
        int n=strlen(a);
        long long int ans=0;
        for(int i=0;i<n;i++){
    
            ans<<=4;
            ans+=f(a[i]);
        }
        printf("%lld\n",ans);
    //}
    return 0;
}

BASIC-12 十六进制转八进制

#include<bits/stdc++.h>
using namespace std;
#define maxn 100052
char a[maxn];
bool c[maxn*4]={
    0};
int ans[maxn*2];
int f(char x){
    
    if(x>='A'&&x<='F')return x-'A'+10;
    else return x-'0';
}
int main(){
    
    int T;
    scanf("%d",&T);
    while(T--){
    
        scanf("%s",a);
        int n=strlen(a);
        for(int i=n-1,j=0;i>=0;i--,j+=4){
    
            int x=f(a[i]);
            c[j]=x&1;
            c[j+1]=(x>>1)&1;
            c[j+2]=(x>>2)&1;
            c[j+3]=(x>>3)&1;
        }
        int cnt=0;
        for(int i=0;i<n*4;i+=3){
    
            ans[cnt++]=(c[i])+ (c[i+1]<<1)+ (c[i+2]<<2);
        }
        bool flag=0;
        for(int i=cnt-1;i>=0;i--){
    
            if(ans[i]!=0)flag=1;
            if(flag)printf("%d",ans[i]);
        }
        printf("\n");
    }
    return 0;
}

BASIC-13 数列排序

#include<bits/stdc++.h>
using namespace std;
int a[19000];
int main(){
    
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        scanf("%d",&a[i]);
    }
    sort(a,a+n);
    for(int i=0;i<n;i++){
    
        if(i!=0)printf(" ");
        printf("%d",a[i]);
    }
    return 0;
}


二、算法训练

ALGO-1 区间k大数查询

ALGO-2 最大最小公倍数

ALGO-3 K好数

ALGO-4 结点选择

ALGO-5 最短路

ALGO-6 安慰奶牛

ALGO-7 逆序对

ALGO-8 操作格子

ALGO-42 送分啦

ALGO-48 关联矩阵

ALGO-49 寻找数组中最大值

ALGO-51 Torry的困惑(基本型)

ALGO-53 最小乘积(基本型)

ALGO-79 删除数组零元素

ALGO-81 动态数组使用

ALGO-84 大小写转换

ALGO-86 矩阵乘法

ALGO-87 字串统计

ALGO-90 出现次数最多的整数

ALGO-91 Anagrams问题

ALGO-92 前缀表达式

ALGO-95 2的次幂表示

ALGO-97 排序

ALGO-101 图形显示

ALGO-116 最大的算式

ALGO-122 未名湖边的烦恼

ALGO-124 数字三角形

ALGO-128 Cowboys

ALGO-131 Beaver’s Calculator

ALGO-133 Tricky and Clever Password

ALGO-135 Multithreading

ALGO-137 Lift and Throw

ALGO-142 P1103

ALGO-148 5-1最小公倍数

ALGO-150 6-1 递归求二项式系数值

ALGO-155 C++ CH08 01

ALGO-156 表达式计算

ALGO-159 P0103

ALGO-161 Abbott’s Revenge

ALGO-162 Airport Configuration

ALGO-164 Pollution Solution

ALGO-165 Glenbow Museum

ALGO-170 A Linking Loader

ALGO-176 Bus Tour

ALGO-177 Balloons in a Box

ALGO-178 The Traveling Judges Problem

ALGO-183 Eurodiffusion

ALGO-184 Collecting Luggage

ALGO-189 P0505

ALGO-190 素因子去重

ALGO-193 Password Suspects

ALGO-194 审美课


四、算法提高

ADV-1 两条直线

简记:想到一个三分套三分确定坐标的办法,时间复杂度O(n*log(1e10)*log(1e10))的办法,过了60%的数据。

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 100005;
const double eps = 0.01;
struct point{
    
    int x,y;
}a[maxn];
int n;
int x_max=-inf ,x_min=inf ,y_max=-inf, y_min=inf;
double cla(double x, double y){
    
    double ret=0;
    for(int i=0;i<n;i++){
    
        double now=min(fabs(a[i].x-a[i].y+y-x), fabs(-a[i].x-a[i].y+x+y));
        ret=max(ret, now);
    }
    return ret;
}
double fy(double x, double l, double r){
    
    double midl,midr,e;
    while(r-l>eps){
    
        //printf("ly=%.4lf ry=%.4lf\n",l,r);
        e=(r-l)/3;
        midl=l+e;
        midr=midl+e;
        double ansl=cla(x, midl);
        double ansr=cla(x, midr);
        if(ansl<ansr){
    
            r=midr;
        }
        else{
    
            l=midl;
        }
    }
    return cla(x, l);
}
double fx(double l, double r){
    
    double midl,midr,e;
    while(r-l>eps){
    
        //printf("lx=%.4lf rx=%.4lf\n",l,r);
        e=(r-l)/3;
        midl=l+e;
        midr=midl+e;
        double ansl=fy(midl, y_min, y_max);
        double ansr=fy(midr, y_min, y_max);
        if(ansl<ansr){
    
            r=midr;
        }
        else{
    
            l=midl;
        }
    }
    return fy(l, y_min, y_max);
}
int main(){
    
    scanf("%d",&n);
    double lx,ly,rx,ry;
    for(int i=0;i<n;i++){
    
        scanf("%d%d",&a[i].x, &a[i].y);
        x_min=min(x_min, a[i].x);
        x_max=max(x_max, a[i].x);
        y_min=min(y_min, a[i].y);
        y_max=max(y_max, a[i].y);
    }
    //printf("%.4lf %.4lf\n",(double)x_min,(double)x_max);
    printf("%.1lf\n",fx(x_min, x_max));
    return 0;
}

ADV-15 最大乘积

#include<bits/stdc++.h>
using namespace std;
const int maxn =100;
int a[maxn],n,m;
bool vis[maxn];
typedef long long int qq;
qq ans;
void dfs(int x, qq s){
    
    if(x==m){
    
        ans=max(ans,s);
        return ;
    }
    for(int i=0;i<n;i++){
    
        if(vis[i])continue;
        vis[i]=1;
        dfs(x+1, s*a[i]);
        vis[i]=0;
    }
}
int main(){
    
    int T;
    scanf("%d",&T);
    while(T--){
    
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++){
    
            scanf("%d",&a[i]);
        }
        ans=-100000;
        memset(vis,0,sizeof(vis));
        dfs(0,1);
        printf("%lld\n",ans);
    }
    return 0;
}

ADV-94 复数归一化

#include<bits/stdc++.h>
using namespace std;

int main(){
    
    int a,b;
    while(scanf("%d%d",&a,&b)!=EOF){
    
        printf("%.1lf+%.1lfi\n",a/sqrt(a*a+b*b) , b/sqrt(a*a+b*b));
    }
    return 0;
}

ADV-97 十进制数转八进制数

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;

int main(){
    
    qq n;
    scanf("%lld",&n);
    int a[100]={
    0},cnt=0;
    while(n>0){
    
        a[cnt++]=n%8;
        n/=8;
    }
    for(int i=cnt-1;i>=0;i--){
    
        printf("%d",a[i]);
    }
    printf("\n");
    return 0;
}

ADV-98 约数个数

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;

int main(){
    
    int n,ans=0;
    scanf("%d",&n);
    for(int i=1;i*i<n;i++){
    
        if(n%i==0)ans+=2;
    }
    int t=sqrt(n);
    if(t*t==n)ans++;
    printf("%d\n",ans);
    return 0;
}


ADV-100 第二大整数

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100;
const int inf = 0x3f3f3f3f;
int main(){
    
    int n,ans=-inf,temp=-inf;
    while(scanf("%d",&n)!=EOF){
    
        if(n==0){
    
            printf("%d\n",ans);
            return 0;
        }
        if(n>=temp){
    
            ans=temp;
            temp=n;
        }
        else if(n>=ans){
    
            ans=n;
        }
    }
    printf("%d\n",ans);
    return 0;
}

ADV-197 P1001

#include<bits/stdc++.h>
using namespace std;

int main(){
    
    long long int a,b;
    scanf("%lld%lld",&a,&b);
    printf("%lld\n",a*b);
    return 0;
}

ADV-223 8-1因式分解

#include<bits/stdc++.h>
using namespace std;
int main(){
    
    int n;
    scanf("%d",&n);
    bool flag=0;
    for(int i=2;i*i<=n;i++){
    
        while(n%i==0){
    
            if(flag==1){
    
                printf("*");
            }
            printf("%d",i);
            n/=i;
            flag=1;
        }
    }
    if(n!=1){
    
        if(flag==1){
    
            printf("*");
        }
        printf("%d",n);
    }
    return 0;
}

ADV-232 矩阵乘法

简记:动态规划

#include<bits/stdc++.h>
using namespace std;
#define maxn 1005
typedef long long int qq;
int n;
qq a[maxn],dp[maxn][maxn];
qq f(int l,int r){
    
    if(l==r)return 0;
    if(dp[l][r]!=-1)return dp[l][r];
    qq ret=-1;
    for(int i=l;i<r;i++){
    
        qq x= f(l,i)+ f(i+1,r)+ a[l-1]*a[i]*a[r] ;
        if(ret==-1||ret>x) ret=x;
    }
    return dp[l][r]=ret;
}
qq f2(int n){
    
    memset(dp,-1,sizeof(dp));
    for(int i=0;i<=n;i++)dp[i][i]=0;
    for(int k=1;k<n;k++){
    
        for(int l=1;l<=n;l++){
    
            if(l+k>n)break;
            for(int mid=l;mid<l+k;mid++){
    
                qq x= dp[l][mid]+ dp[mid+1][l+k] + a[l-1]*a[mid]*a[l+k];
                if(dp[l][l+k]>x||dp[l][l+k]==-1)
                    dp[l][l+k]=x;
            }
        }
    }
    return dp[1][n];
}
int main(){
    
    memset(dp,-1,sizeof(dp));
    scanf("%d",&n);
    for(int i=0;i<=n;i++){
    
        scanf("%lld",&a[i]);
    }
    //qq ans=f(1,n);
    qq ans=f2(n);
    printf("%lld\n",ans);
    return 0;
}


五、历届试题

PREV-1 核桃的数量

#include<bits/stdc++.h>
using namespace std;
int lcm(int x,int y){
    
    return x*y/__gcd(x,y);
}
int main(){
    
    int a,b,c;
    while(scanf("%d%d%d",&a,&b,&c)!=EOF){
    
        printf("%d\n",lcm(lcm(a,b),c));
    }
}

PREV-2 打印十字图

#include<bits/stdc++.h>
using namespace std;
const int bas = 500;
int a[bas][bas];
int mov[8][2]={
    {
    1,0},{
    -1,0},{
    0,1},{
    0,-1},{
    1,1},{
    1,-1},{
    -1,1},{
    -1,-1}};
bool vis[bas][bas];
void print(int n){
    
    memset(a,-1,sizeof(a));
    int mid=n/2;
    a[mid][mid]=1;
    a[mid+1][mid]=1;a[mid+2][mid]=1;a[mid-1][mid]=1;a[mid-2][mid]=1;
    a[mid][mid+1]=1;a[mid][mid+2]=1;a[mid][mid-1]=1;a[mid][mid-2]=1;
    for(int i=0;i<100;i++){
    
        memset(vis,0,sizeof(vis));
        for(int x=0;x<n;x++)for(int y=0;y<n;y++){
    
            if(a[x][y]!=-1)continue;
            int flag=0;
            for(int c=0;c<8;c++){
    
                int tx=x+mov[c][0], ty=y+mov[c][1];
                if(tx<0||tx>=n||ty<0||ty>=n||a[tx][ty]==-1)continue;
                flag=1;
            }
            if(flag==1){
    
                vis[x][y]=1;
            }
        }
        for(int x=0;x<n;x++)for(int y=0;y<n;y++){
    
            if(vis[x][y]==1){
    
                if(i&1) a[x][y]=1;
                else a[x][y]=0;
            }
        }
    }
    a[0][n-1]=!(n&1);
    a[0][0]=!(n&1);
    a[n-1][n-1]=!(n&1);
    a[n-1][0]=!(n&1);
}
int main(){
    
    int n;
    while(scanf("%d",&n)!=EOF){
    
        print(4*n+5);
        for(int i=0;i<4*n+5;i++){
    
            for(int j=0;j<4*n+5;j++){
    
                if(a[i][j]==0)printf(".");
                else printf("$");
            }
            printf("\n");
        }
    }

    return 0;
}

PREV-3 带分数

简记:若强行跑O(11!)的时间复杂度再O(11)判断是否可行,会超时,需要在dfs过程中,通过维护已经得到的值来剪枝。

#include<bits/stdc++.h>
using namespace std;
#define maxn 15
const int bas = 11;
int ans=0, n, a[maxn], vis[maxn];
void print(){
    
    for(int i=0;i<bas;i++){
    
        if(a[i]==0)printf("+");
        else if(a[i]==10)printf("/");
        else printf("%d",a[i]);
    }
    printf("\n");
}
int cla(){
    
    int ret=-1;
    int flag=0, now=0, mot=0;//是否出现过'/'
    for(int i=0;i<bas;i++){
    
        if(a[i]==0){
    //出现'+'
            if(now==0)return -1;
            ret=now;
            now=0;
        }
        else if(a[i]==10){
    //出现'/'
            if(now==0)return -1;
            mot=now;
            now=0;
        }
        else {
    
            now=now*10+a[i];
        }
    }
    if((mot%now!=0)||(now==0))return -1;
    //print();
    return ret+mot/now;
}
void dfs(int x, int op, int s, int son, int mot){
    //0son 1mot 2s
    if(x==11){
    
        if(op!=2)return;
        if((s==0)||(son%mot!=0))return;
        if(s+son/mot==n) ans++;
        return ;
    }
    for(int i=0;i<bas;i++){
    
        int top=op, ts=s, tson=son, tmot=mot;
        if(vis[i]==1)continue;
        if(i==0){
    //'+'
            if(op!=1||mot==0)continue;
            if(son%mot!=0||son/mot>n)continue;
            top=2;
        }
        else if(i==10){
    //'/'
            if(op!=0)continue;
            if(son==0)continue;
            top=1;
        }
        else{
    
            if(op==0)tson=son*10+i;
            else if(op==1)tmot=mot*10+i;
            else ts=s*10+i;
        }
        vis[i]=1;
        //a[x]=i;
        dfs(x+1, top, ts, tson, tmot);
        vis[i]=0;
    }
}
int main(){
    
    while(scanf("%d",&n)!=EOF){
    
        ans=0;
        memset(vis,0,sizeof(vis));
        dfs(0,0,0,0,0);
        printf("%d\n",ans);
    }
    return 0;
}

PREV-4 剪格子

简记:一开始理解错了题意,后来百度的其他人方法,发现是一个玄学的dfs+剪枝,最差时间复杂度为:O(2^n*m)。认为没必要费时间练这题~

#include<bits/stdc++.h>
using namespace std;
int n,m, a[20][20], ans, sum;
int mov[4][2]={
    {
    1,0},{
    -1,0},{
    0,1},{
    0,-1}};
bool vis[20][20];
void dfs(int x, int y, int s, int dep){
    
    if(dep>=ans||s>sum)return;
    if(s==sum){
    
        /*for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++){
                if(vis[i][j])printf("%d ",a[i][j]);
                else printf("0 ");
            }
            printf("\n");
        }*/
        ans=dep;
        return;
    }
    for(int i=0;i<4;i++){
    
        int tx=x+mov[i][0], ty=y+mov[i][1];
        if(tx<=0||tx>n||ty<=0||ty>m)continue;
        if(vis[tx][ty])continue;
        vis[tx][ty]=1;
        dfs(tx,ty,s+a[tx][ty],dep+1);
        vis[tx][ty]=0;
    }
}
int main(){
    
    scanf("%d%d",&m,&n);
    ans=n*m;
    sum=0;
    for(int i=1;i<=n;i++){
    
        for(int j=1;j<=m;j++){
    
            scanf("%d",&a[i][j]);
            sum+=a[i][j];
        }
    }
    if(sum&1){
    
        printf("0\n");
        return 0;
    }
    sum/=2;
    memset(vis,0,sizeof(vis));
    vis[1][1]=1;
    dfs(1,1,a[1][1],1);
    if(ans==n*m)printf("0\n");
    else printf("%d\n",ans);
    return 0;
}

PREV-5 错误票据

简记:读入有些技巧,如果明白文件输入输出原理的话,会方便不少。

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000
int a[maxn],num[maxn];
int main(){
    
    int n,x;
    scanf("%d",&n);
    n=0;
    while(scanf("%d",&x)!=EOF){
    
        a[n++]=x;
    }
    sort(a,a+n);
    int ans=-1,ans2=-1;
    for(int i=1;i<n;i++){
    
        if(a[i]==a[i-1])ans2=a[i];
        if(a[i]!=a[i-1]+1&&a[i]!=a[i-1])ans=a[i]-1;
    }
    printf("%d %d\n",ans,ans2);
    return 0;
}

PREV-6 翻硬币

#include<bits/stdc++.h>
using namespace std;
#define maxn 1052
char s[maxn];
int a[maxn],b[maxn];
int main(){
    
    int n;
    scanf("%s",s);
    n=strlen(s);
    for(int i=0;i<n;i++){
    
        if(s[i]=='o')a[i]=0;
        else a[i]=1;
    }
    scanf("%s",s);
    for(int i=0;i<n;i++){
    
        if(s[i]=='o')b[i]=0;
        else b[i]=1;
    }
    int ans=0;
    for(int i=0;i<n-1;i++){
    
        if(a[i]!=b[i]){
    
            ans++;
            a[i+1]=!a[i+1];
        }
    }
    if(a[n-1]!=b[n-1])printf("-1\n");//应该是不可能不能成功
    else printf("%d\n",ans);
    return 0;
}

PREV-7 连号区间数

简记:n方暴力就可以过,没想到巧妙地枚举方法可以做到nlogn。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100052;
int a[maxn];
int main(){
    
    int ans,n;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        scanf("%d",&a[i]);
    }
    ans=0;
    for(int l=0;l<n;l++){
    
        ans++;
        int min0=a[l], max0=a[l];
        for(int r=l+1;r<n;r++){
    
            min0=min(min0,a[r]);
            max0=max(max0,a[r]);
            if(max0-min0==r-l)ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

PREV-8 买不到的数目

/*
题目大意:输入两个数:a,b,找出最大的c满足c不能表示成an+bm(n,m∈N*) 
思路:打表找规律
*/
#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;
int dp[1050]={
    0};

int main()
{
    
	int a,b;
	cin>>a>>b;
	if(a>b)//a<b
	{
    
		int c=a;
		a=b;
		b=c;
	}
	int maxx=0;
	for(int i=1;i<b;i++)
	{
    	
		int x=i;
		while(1)
		{
    
			if(x%a==0)break;
			x+=b;
		}
		//cout<<i<<" "<<x<<endl;
		if(maxx<x)maxx=x;
	}
	
	cout<<maxx-b;
	return 0;
}

PREV-9 大臣的旅费

简记:
1.问题等价于求一棵树的重心
2.实测点数n<=10000,最大路费不超过signed int。

#include<bits/stdc++.h>
using namespace std;
#define maxn 10052
struct node{
    
    int pos,val;
    node(){
    }
    node(int p, int v){
    
        pos=p;  val=v;
    }
};
int f(int x){
    
    return x*10+(1+x)*x/2;
}
vector<node>u[maxn];
int dis[maxn];
int dfs(int x, int fa, int h){
    
    for(int i=0;i<u[x].size();i++){
    
        if(u[x][i].pos==fa)continue;
        dfs(u[x][i].pos, x, h+u[x][i].val);
    }
    return dis[x]=h;
}
int main(){
    
    int n;
    scanf("%d",&n);
    for(int i=0;i<n-1;i++){
    
        int s,t,w;
        scanf("%d%d%d",&s,&t,&w);
        u[s].push_back(node(t,w));
        u[t].push_back(node(s,w));
    }
    dfs(1, -1, 0);
    int root=0;
    for(int i=1;i<=n;i++){
    
        if(root==0||dis[i]>dis[root])root=i;
    }
    //printf("root=%d\n",root);
    dfs(root, -1, 0);
    int ans=0;
    for(int i=1;i<=n;i++){
    
        if(ans==0||dis[i]>dis[ans])ans=i;
    }
    //printf("ans=%d\n",ans);
    printf("%d\n",f(dis[ans]));
    return 0;
}

PREV-10 幸运数

简记:
1.一般这种求区间[L,R]之间个数的,变成求[1,R]个数-[1,L-1]个数。
2.乍一看,平均下来每次压缩是个logn级别的操作,权当一试。
3.1e6超时,5e5优化到了极致,可以通过数据,但是应该还是有问题,我觉得是题目问题。

#include<bits/stdc++.h>
using namespace std;
#define maxn 500052
int a[maxn];
int f(int x, int len){
    //将a数组中下标为x的倍数的位置的数字删除,返回数组长度
    if(x>len)return len;
    int cnt=x;
    for(int i=x;i<=len;i++){
    
        if(i%x==0)continue;
        a[cnt++]=a[i];
    }
    a[cnt]=0;
    return cnt-1;
}
int init(){
    
    int ret=1;
    int len=maxn/2;
    for(int i=1;i<=len;i++){
    
        a[i]=i*2-1;
    }
    ret++;
    while(a[ret]!=0){
    
        if(a[ret]>len)break;
        /*printf("ans[%d]=%d  ",ret,a[ret]);
        for(int i=1;i<=len;i++){
            printf("%d ",a[i]);
        }
        printf("\n");*/
        len=f(a[ret], len);
        ret++;
    }
    return ret;
}
int main(){
    
    init();
    int n,m;
    scanf("%d%d",&n,&m);
    int ans=0,flag=0;
    for(int i=0;a[i]<m;i++){
    
        if(a[i]>n)flag=1;
        if(flag==1)ans++;
    }
    printf("%d\n",ans);
}

PREV-11 横向打印二叉树

简记:
这次练一下指针形式建树。这个横向输出实在麻烦,预声明了二维字符数组,递归画出,最后输出。

#include<bits/stdc++.h>
using namespace std;
#define maxn 1052
struct node{
    
    int data,size;
    node *l, *r;
};
node *build_node(int data){
    
    node *ret=new node;
    ret->data=data;
    ret->l=NULL;
    ret->r=NULL;
    ret->size=1;
}
struct sort_tree{
    
    int pos[10052];//pos[x]表示x为第pos[x]大
    node *root=new node;
    bool empty=1;
    int size=0, cnt;
    char mp[105][1000];
    void draw(node *o, int y, bool flag){
    //第y列加入o
        int now=o->data, x=pos[o->data], ty=y, k=0;
        char p[10]={
    0};
        while(now>0){
    
            p[k++]=now%10+'0';
            now/=10;
        }
        if(flag==0){
    
            mp[x][ty++]='-';
        }
        for(int i=k-1;i>=0;i--,ty++){
    //画数字
            mp[x][ty]=p[i];
        }
        if(o->l!=NULL||o->r!=NULL){
    //画后缀“-|”
            mp[x][ty++]='-';
            mp[x][ty]='|';
        }
        if(o->l!=NULL)//向下画‘|’
            for(int i=x;i<=pos[o->l->data];i++){
    
                mp[i][ty]='|';
            }
        if(o->r!=NULL)//向上画‘|’
            for(int i=pos[o->r->data];i<=x;i++){
    
                mp[i][ty]='|';
            }
        if(o->l!=NULL||o->r!=NULL)ty++;
        mp[x][ty]='\0';

        if(o->r!=NULL){
    //画右子树
            draw(o->r, ty, 0);
        }
        if(o->l!=NULL){
    //画左子树
            draw(o->l, ty, 0);
        }
    }
    void out(){
    
        for(int i=0;i<=size;i++){
    
            for(int j=0;j<1000;j++){
    
                mp[i][j]='.';
            }
        }
        draw(root, 0, 1);
        for(int i=1;i<=size;i++){
    
            printf("%s\n",mp[i]);
        }
    }
    void print(node *x){
    
        if(x->r!=NULL){
    
            print(x->r);
        }
        //printf("%d ",x->data);
        pos[x->data]=cnt++;
        if(x->l!=NULL){
    
            print(x->l);
        }
    }
    void print(){
    
        memset(pos,-1,sizeof(pos));
        cnt=1;
        print(root);
    }
    void add(node *x, int v){
    
        x->size++;
        if(x->data >v){
    
            if(x->l==NULL) x->l= build_node(v);
            else add(x->l, v);
        }
        else {
    
            if(x->r==NULL) x->r= build_node(v);
            else add(x->r, v);
        }
    }
    void add(int v){
    
        size++;
        if(empty){
    
            root->data=v;
            root->l=NULL;
            root->r=NULL;
            root->size=1;
            empty=0;
        }
        else add(root, v);
    }
};
int main()
{
    
    //freopen("in.txt","r",stdin);
    sort_tree x;
    int n;
    while(scanf("%d",&n)!=EOF){
    
        x.add(n);
    }
    x.print();
    x.out();
    return 0;
}

PREV-12 危险系数

简记:
依次在图中删除每一个点,判断s到t是否依然连通,时间复杂度O(n*m)。直觉感觉应该是还有更快的办法,没认真想。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1005;
const int maxm = 2005;
struct Graph{
    
    vector<int>a[maxn];
    bool vis[maxn];
    int n,m;
    void input(){
    
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
    
            int ss,tt;
            scanf("%d%d",&ss,&tt);
            a[ss].push_back(tt);
            a[tt].push_back(ss);
        }
    }
    void dfs(int x, int del){
    
        vis[x]=1;
        for(int i=0;i<a[x].size();i++){
    
            if(a[x][i]==del|| vis[a[x][i]]) continue;
            dfs(a[x][i], del);
        }
    }
    int cla(int s, int t){
    
        int ret=0;
        for(int i=1;i<=n;i++){
    
            if(i==s||i==t)continue;
            memset(vis,0,sizeof(vis));
            dfs(s, i);
            if(vis[t]==0)ret++;
        }
        return ret;
    }
};
int main(){
    
    Graph ans;
    ans.input();
    int s,t;
    scanf("%d%d",&s,&t);
    printf("%d\n",ans.cla(s,t));
    return 0;
}

PREV-13 网络寻路

简记:
枚举每条边(u,v),以这条边为中间边的合法边数为:(和u相连的点数-1)*(和v相连的点数-1)

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
const int node_size = 10005;
const int edge_size = 100005;
struct Graph{
    
    vector<int>u[node_size];
    int n,m;
    void clear(){
    
        for(int i=0;i<node_size;i++){
    
            u[i].clear();
        }
    }
    void add_edge(int s, int t){
    
        u[s].push_back(t);
        u[t].push_back(s);
    }
    void input(){
    
        scanf("%d%d",&n,&m);
        for(int i=0;i<m;i++){
    
            int ss,tt;
            scanf("%d%d",&ss,&tt);
            add_edge(ss,tt);
        }
    }
    qq cla(){
    
        qq ret=0;
        for(int i=1;i<=n;i++){
    
            for(int j=0;j<u[i].size();j++){
    
                ret+=(u[i].size()-1)*(u[u[i][j]].size()-1);
            }
        }
        return ret;
    }
};
int main(){
    
    Graph ans;
    ans.clear();
    ans.input();
    printf("%lld\n",ans.cla());
    return 0;
}

PREV-14 高僧斗法

简记:
首先两两组合看成nim博奕问题,奇数个就在最高点加一个。但是目标是一定要优先移动最左边的。有个坑点,对于一对点,可以变大也可以变小。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 10005;
int a[maxn],c[maxn],n;
int main(){
    
    n=0;
    while(scanf("%d",&a[n])!=EOF){
    
        n++;
    }
    if(n&1){
    
        a[n]=a[n-1]+1;
        n++;
    }
    int ans=0;
    for(int i=0,j=0;i<n;j++,i+=2){
    
        c[j]=a[i+1]-a[i]-1;
        ans^=c[j];
    }
    //printf("ans=%d\n",ans);
    if(ans==0){
    
        printf("-1\n");
    }
    else{
    
        int m=n/2;
        for(int i=0;i<m;i++){
    
            int t=ans^c[i];
            if(t<c[i]){
    
                printf("%d %d",a[i*2],a[i*2]+c[i]-t);
                break;
            }
            else if(i*2+2<n&& a[i*2]+t+1<a[i*2+2]){
    
                printf("%d %d",a[i*2+1],a[i*2]+t+1);
                break;
            }
        }
    }
    return 0;
}

PREV-15 格子刷油漆

简记:动态规划

#include <bits/stdc++.h>
using namespace std;
typedef long long qq;
const qq mod = 1000000007;
const int maxn = 1005;

qq a[maxn];
qq b[maxn];//不能直接使用公式,会超出范围
int main()
{
    
	int n;
	scanf("%d",&n);
	if(n==1)
	{
    
		printf("2\n");
		return 0;
	}

	memset(a,0,sizeof(a));
	b[1]=1;
	for(int i=2;i<=n;i++)
	{
    
		b[i]=b[i-1]*2%mod;
    }
	a[1]=1;a[2]=6;
	for(int i=3;i<=n;i++)
	{
    
		a[i]=a[i-2]*4+a[i-1]*2+b[i];
		a[i]%=mod;
	}
	qq sum=0;
	for(int i=2;i<n;i++)
	{
    
		sum+=(b[n-i+1]*a[i-1] + b[i]*a[n-i]) *4;
		sum%=mod;
	}
	sum+=a[n]*4;
	sum%=mod;
	printf("%lld\n", sum);
	return 0;
}

PREV-19 九宫重排

简记:记好状态BFS即可

#include<bits/stdc++.h>
using namespace std;
const int bas = 3;
const int mov[4][2]={
    {
    0,1},{
    0,-1},{
    1,0},{
    -1,0}};
map<int,bool>vis;
struct state{
    
    int a[bas][bas];
    int hast, posx, posy, step;
    int hash(){
    
        int ret=0;
        for(int x=0;x<bas;x++)
        for(int y=0;y<bas;y++){
    
            ret=ret*10+a[x][y];
        }
        return ret;
    }
    state f(int op){
    
        state ret= *this;
        int tx=posx+mov[op][0], ty=posy+mov[op][1];
        if(tx<0||tx>=bas||ty<0||ty>=bas){
    
            ret.hast=-1;
            return ret;
        }
        swap(ret.a[posx][posy], ret.a[tx][ty]);
        ret.posx=tx, ret.posy=ty;
        ret.step++;
        ret.hast=ret.hash();
        return ret;
    }
    void input(){
    
        char temp[15];
        scanf("%s",temp);
        for(int i=0;i<9;i++){
    
            if(temp[i]=='.') {
    
                this->posx=i/3, this->posy=i%3;
                this->a[i/3][i%3]=0;
            }
            else this->a[i/3][i%3]=temp[i]-'0';
        }
        this->step=0;
        this->hast=this->hash();
    }
    void out(){
    
        printf("hast=%d\n",this->hast);
        for(int i=0;i<bas;i++){
    
            for(int j=0;j<bas;j++){
    
                printf("%d ",a[i][j]);
            }
            printf("\n");
        }
        printf("\n");
    }
};
int bfs(state s, state t){
    
    queue<state>q;
    q.push(s);
    vis[s.hast]=1;
    while(!q.empty()){
    
        state now=q.front();
        //now.out();
        q.pop();
        for(int i=0;i<4;i++){
    
            state x=now.f(i);
            if(x.hast==-1||vis.count(x.hast)!=0){
    
                continue;
            }
            if(x.hast==t.hast)return x.step;
            vis[x.hast]=1;
            q.push(x);
        }
    }
    return -1;
}
int main(){
    
    state s,t;
    s.input();
    t.input();
    cout<<bfs(s,t)<<endl;
    return 0;
}

PREV-21 回文数字

#include<bits/stdc++.h>
using namespace std;
int n;
bool f(int x){
    
    int a[100],cnt=0;
    int ret=0;
    while(x>0){
    
        a[cnt++]=x%10;
        ret+=a[cnt-1];
        x/=10;
    }
    if(ret!=n)return 0;
    for(int i=0;i<cnt/2;i++){
    
        if(a[i]!=a[cnt-1-i])return 0;
    }
    return 1;
}
int main(){
    
    while(scanf("%d",&n)!=EOF){
    
        int flag=0;
        for(int i=10000;i<1000000;i++){
    
            if(f(i)){
    
                flag=1;
                printf("%d\n",i);
            }
        }
        if(flag==0){
    
            printf("-1\n");
        }
    }
    return 0;
}

PREV-22 国王的烦恼

简记:经典的并查集问题,首先把边根据失去的时间点排序,返向连接,如果连接边ab的时候,发现连接前ab之间不可达,那么这一天就会有人抗议。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100052;
bool vis[maxn];
struct Edge{
    
    int v1,v2,t;
}v[maxn];
bool operator <(Edge a, Edge b){
    
    return a.t > b.t;
}
struct tree_set{
    
    int fa[maxn/10],size;
    void init(int x){
    
        size=x;
        for(int i=1;i<=x;i++){
    
            fa[i]=i;
        }
    }
    int f(int x){
    
        if(fa[x]!=x) return fa[x]=f(fa[x]);
        else return fa[x];
    }
    bool Is_connect(int x, int y){
    //x,y是否已经相连
        if(f(x)==f(y))return 1;
        else return 0;
    }
    bool merge(int x, int y){
    //x,y两点合并
        if(Is_connect(x,y) )return 0;//连接失败,本来就相连
        fa[f(x)]=f(y);
        return 1;
    }
};
int main(){
    
    memset(vis,0,sizeof(vis));
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=0;i<m;i++){
    
        scanf("%d%d%d",&v[i].v1, &v[i].v2, &v[i].t);
    }
    sort(v,v+m);
    tree_set x;
    x.init(n);
    int ans=0;
    for(int i=0;i<m;i++){
    
        if(x.Is_connect(v[i].v1, v[i].v2))continue;
        else {
    
            x.merge(v[i].v1, v[i].v2);
            if(!vis[v[i].t])ans++;
            vis[v[i].t]=1;
        }
    }
    printf("%d\n",ans);
    return 0;
}

PREV-23 数字游戏

简记:
当前n个人围成一个环,第一个人从1开始报数,顺次每个人说的的数字加1。现在计算第一个人前t次所报数目的总和为多少。(报数过程在模k的完全剩余系中进行),显然:f(n)= n*(n-1)/2+1
注:取模小小小技巧,小心坑点

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
qq f(qq x,qq k){
    
    if(x&1){
    
        return ((((x-1)/2)%k)*(x%k)+1)%k;
    }
    else return (((x/2)%k)*((x-1)%k)+1)%k;
}
int main(){
    
    qq n,k,t;
    scanf("%lld%lld%lld",&n,&k,&t);
    qq ans=0,x=1;
    for(int i=1;i<=t;i++,x=x+n){
    
        ans+=f(x,k);
    }
    printf("%lld\n",ans);
    return 0;
}

PREV-25 城市建设

简记:
显然的最小生成树问题,对于河流,就看成是一个节点,每个点建码头就是向该点连一条边。
注意有坑点:
1.分别跑一次没有河流的n个点的最小生成树和一次有河流的n+1个点的最小生成树
2.边权小于0的边一定要选,只赚不亏。所以只能用kruskal

#include<bits/stdc++.h>
using namespace std;
const int node_size = 10005;
const int edge_size = 100005;
const int inf = 0x3f3f3f3f;
struct edge{
    
    int s,t,w;
    edge(){
    };
    edge(int ss, int tt, int ww){
    
        s=ss;   t=tt;   w=ww;
    }
};
bool operator < (edge l, edge r){
    
    return l.w< r.w;
}
struct tree_set{
    
    int fa[node_size],size;
    void init(int x){
    
        size=x;
        for(int i=1;i<=x;i++){
    
            fa[i]=i;
        }
    }
    int f(int x){
    
        if(fa[x]!=x) return fa[x]=f(fa[x]);
        else return fa[x];
    }
    bool Is_connect(int x, int y){
    //x,y是否已经相连
        if(f(x)==f(y))return 1;
        else return 0;
    }
    bool merge(int x, int y){
    //x,y两点合并
        if(Is_connect(x,y) )return 0;//连接失败,本来就相连
        fa[f(x)]=f(y);
        return 1;
    }
};
struct Graph{
    
    vector<edge>u[node_size];
    vector<edge>a;
    int n,m;//点数
    void add_edge(edge x){
    
        u[x.s].push_back(x);
        int temp=x.s;  x.s=x.t;    x.t=temp;
        u[x.s].push_back(x);
        a.push_back(x);
    }
    void clear(){
    
        n=0,m=0;
        for(int i=0;i<node_size;i++){
    
            u[i].clear();
        }
        a.clear();
    }
    void input(){
    
        clear();
        scanf("%d%d",&n,&m);
        int mm=m;
        while(mm--){
    
            int ss,tt,ww;
            scanf("%d%d%d",&ss,&tt,&ww);
            add_edge( edge(ss,tt,ww) );
        }
    }
    bool vis[node_size];
    int prim(){
    //求最小生成树,如果不存在就返回inf
        memset(vis,0,sizeof(vis));
        int ret=0,k=1;
        priority_queue<edge>p;
        for(int i=0;i<u[1].size();i++){
    
            p.push(u[1][i]);
        }
        vis[1]=1;
        while(k<n){
    
            if(p.empty())return inf;
            edge now= p.top();
            while(vis[now.t]){
    
                p.pop();
                if(p.empty())return inf;
                now= p.top();
            }
            if(vis[now.t]) return inf;//不连通
            vis[now.t]=1;
            ret+=now.w;
            k++;
            for(int i=0;i<u[now.t].size();i++){
    
                p.push(u[now.t][i]);
            }
        }
        return ret;
    }
    bool cmp_kruskal(edge a, edge b){
    
        return a.w< b.w;
    }
    int kruskal(){
    
        int ret=0,k=0;
        sort(a.begin(),a.end());
        tree_set p;
        p.init(n);
        for(int i=0;i<a.size();i++){
    
            if(a[i].w<0){
    
                ret+=a[i].w;
                k+=p.merge(a[i].s,a[i].t);
                continue;
            }
            if(!p.Is_connect(a[i].s, a[i].t)){
    
                ret+=a[i].w;
                k+=p.merge(a[i].s, a[i].t);
            }
            if(k==n-1)return ret;
        }
        if(k==n-1) return ret;
        else return inf;
    }
};
int main(){
    
    Graph ans;
    int x=inf;
    ans.input();
    x=ans.kruskal();
    //printf("x=%d\n",x);
    for(int i=1;i<=ans.n;i++){
    
        int temp=0;
        scanf("%d",&temp);
        if(temp==-1)continue;
        ans.add_edge( edge(i,ans.n+1,temp));
        ans.add_edge( edge(ans.n+1,i,temp));
    }
    ans.n++;
    printf("%d\n",min(x, ans.kruskal()) );
    return 0;
}

PREV-26 最大子阵

简记:算是挺经典的问题了,算一个500500的矩阵的最大子矩阵,相当于枚举使用哪些行O(nn),对每次枚举,求最大子段和O(m)

#include<bits/stdc++.h>
using namespace std;
#define maxn 505
#define inf 0x3f3f3f3f
int sum[maxn][maxn];
int main(){
    
    int n,m,x;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
    
        for(int j=1;j<=m;j++){
    
            scanf("%d",&x);
            sum[i][j]=sum[i-1][j]+x;
        }
    }
    int ans=-inf;
    for(int l=1;l<=n;l++){
    
        for(int r=l;r<=n;r++){
    
            int dp=0;
            for(int i=1;i<=m;i++){
    
                int t=sum[r][i]-sum[l-1][i];
                if(dp>0)dp+=t;
                else dp=t;
                if(dp>ans)ans=dp;
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}

PREV-27 蚂蚁感冒

简记:分类讨论,挺麻烦的,一定要谨慎。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 150;
int n;
struct point{
    
    int x,dir;
}a[maxn],s;
bool operator < (point x, point y){
    
    return x.x< y.x;
}
int main(){
    
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        int x;
        scanf("%d",&x);
        a[i].dir=x/abs(x);
        a[i].x=abs(x);
    }
    s=a[0];
    sort(a,a+n);
    int ans=0;
    /*for(int i=0;i<n;i++){
        printf("(%d %d) ",a[i].x,a[i].dir);
    }*/
    if(s.dir==1){
    //向右
        int pos=-1, c; bool flag=0;
        for(int i=0;i<n;i++){
    
            if(a[i].x==s.x&&a[i].dir==s.dir){
    
                pos=i;break;
            }
        }
        for(int i=pos+1;i<n;i++){
    
            if(a[i].dir*s.dir==-1){
    
                ans++;
                if(flag==0){
    
                    c=i;
                    flag=1;
                }
            }
        }
        if(flag==1){
    
            for(int i=c-1;i>=0;i--){
    
                if(a[i].dir==s.dir&&a[i].x==s.x)continue;
                if(a[i].dir*a[c].dir==-1)ans++;
            }
        }
    }
    else{
    
        int pos=-1, c; bool flag=0;
        for(int i=0;i<n;i++){
    
            if(a[i].x==s.x&&a[i].dir==s.dir){
    
                pos=i;break;
            }
        }
        for(int i=pos-1;i>=0;i--){
    
            if(a[i].dir*s.dir==-1){
    
                ans++;
                if(flag==0){
    
                    c=i;
                    flag=1;
                }
            }
        }
        //printf("ans=%d\n",ans);
        if(flag==1){
    
            for(int i=c+1;i<n;i++){
    
                if(a[i].dir==s.dir&&a[i].x==s.x)continue;
                if(a[i].dir*a[c].dir==-1)ans++;
            }
        }
    }
    printf("%d\n",ans+1);
    return 0;
}

PREV-28 地宫取宝

简记:
1.状态设定: d p ( i , j , k , h ) dp(i,j,k,h) dp(i,j,k,h)表示在点 ( i , j ) (i,j) (i,j),当前手里有 k k k个物品,最大的为 h h h的路径数。
2.状态转移方程:
d p ( i , j , k , h ) = 选 c ( i , j ) + 不 选 c ( i , j ) ; dp(i,j,k,h)=选c(i,j) +不选c(i,j); dp(i,j,k,h)=c(i,j)+c(i,j);
选 c ( i , j ) : d p ( i − 1 , j , k − 1 , [ 0 , h − 1 ] ) + d p ( i , j − 1 , k − 1 , [ 0 , h − 1 ] ) 前 提 h = = c ( i , j ) &amp; &amp; k ! = 0 选c(i,j):dp(i-1,j,k-1,[0,h-1])+dp(i,j-1,k-1,[0,h-1]) 前提 h==c(i,j) \&amp;\&amp; k!=0 c(i,j):dp(i1,j,k1,[0,h1])+dp(i,j1,k1,[0,h1])h==c(i,j)&&k!=0
不 选 c ( i , j ) : d p ( i − 1 , j , k , h ) + d p ( i , j − 1 , k , h ) ; 不选c(i,j):dp(i-1,j,k,h)+dp(i,j-1,k,h); c(i,j):dp(i1,j,k,h)+dp(i,j1,k,h);
3.初始状态:
d p ( 0 , 0 , 0 , 0 ) = 1 ; dp(0,0,0,0)=1; dp(0,0,0,0)=1;
d p ( 0 , 0 , 1 , c ( 0 , 0 ) ) = 1 ; dp(0,0,1,c(0,0))=1; dp(0,0,1,c(0,0))=1;
一个坑点:有的礼物价值会为 0 0 0,转移过程会出问题,解决办法: c [ i ] [ j ] + + ; c[i][j]++; c[i][j]++;

#include<bits/stdc++.h>
using namespace std;
#define MOD 1000000007
#define mod(x) ((x)%MOD)
const int bas = 55;
const int maxn = 15;
typedef long long int qq;
qq dp[bas][bas][bas][maxn];
int n,m,p,c[bas][bas],w;
int main(){
    
    while(scanf("%d%d%d",&n,&m,&p)!=EOF){
    
        w=0;
        for(int i=1;i<=n;i++){
    
            for(int j=1;j<=m;j++){
    
                scanf("%d",&c[i][j]);
                c[i][j]++;
                w=max(w,c[i][j]);
            }
        }
        memset(dp,0,sizeof(dp));
        dp[1][1][0][0]=1;
        dp[1][1][1][c[1][1]]=1;
        for(int i=1;i<=n;i++){
    
        for(int j=1;j<=m;j++){
    
        if(i==1&&j==1)continue;
        for(int k=0;k<=p;k++){
    
        for(int h=0;h<=w;h++){
    
            dp[i][j][k][h]=0;
            if(c[i][j]==h&&k!=0){
    //选c[i][j]
                for(int u=0;u<h;u++){
    
                    dp[i][j][k][h]+=dp[i-1][j][k-1][u]+dp[i][j-1][k-1][u];
                }
            }
            dp[i][j][k][h]=mod(dp[i][j][k][h]+ dp[i-1][j][k][h]+ dp[i][j-1][k][h]);
        }}}}
        qq ans=0;
        for(int i=0;i<=w;i++){
    
            ans+=dp[n][m][p][i];
        }
        printf("%lld\n",mod(ans));
    }
    return 0;
}

PREV-29 斐波那契

简记:
数论类技巧公式,可以打表找规律
g ( x ) = ∑ i = 1 x f ( i ) = f ( n + 2 ) − 1 ; g(x)=\sum_{i=1}^{x}f(i)=f(n+2)-1; g(x)=i=1xf(i)=f(n+2)1;
f ( n ) % f ( m ) = f ( n % m ) ∗ f ( m − 1 ) ⌊ n m ⌋ ; f(n)\%f(m)=f(n\%m)*f(m-1)^{\lfloor\frac nm\rfloor}; f(n)%f(m)=f(n%m)f(m1)mn;
样例没过,但是满分了,最后一点很复杂的分类讨论不想看了~

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
#define mod(x,P) ((x)%P)
#define moc(x,P) (((x)>=P)?((x)-(P)):(x))
struct Mat{
    
    qq a[2][2];
}o,e,u;
qq n,m,p;
qq fast_mul(qq x, qq y, qq p){
    
    qq ret=0;
    x=mod(x,p);
    y=mod(y,p);
    while(x>0){
    
        if(x&1)ret=moc(ret+y,p);
        x>>=1;
        y=moc(y<<1,p);
    }
    return ret;
}
qq fast_pow(qq x, qq k, qq p){
    
    qq ret=1;
    x=mod(x,p);
    while(k>0){
    
        if(k&1)ret=fast_mul(ret,x,p);
        k>>=1;
        x=fast_pow(x,x,p);
    }
    return moc(ret,p);
}
Mat operator * (Mat x, Mat y){
    
    Mat ret=o;
    for(int i=0;i<2;i++){
    
    for(int j=0;j<2;j++){
    
    for(int k=0;k<2;k++){
    
    ret.a[i][j]=moc(ret.a[i][j]+fast_mul(x.a[i][k],y.a[k][j],p), p);
    }}}
    return ret;
}
Mat operator ^ (Mat x, qq k){
    
    Mat ret=e;
    while(k>0){
    
        if(k&1)ret=ret*x;
        k>>=1;
        x=x*x;
    }
    return ret;
}
void init(){
    
    e.a[0][0]=1; e.a[0][1]=0; e.a[1][0]=0; e.a[1][1]=1;
    o.a[0][0]=0; o.a[0][1]=0; o.a[1][0]=0; o.a[1][1]=0;
    u.a[0][0]=1; u.a[0][1]=1; u.a[1][0]=1; u.a[1][1]=0;
}
qq f(qq x){
    
    Mat ret;
    ret=u^(x-1);
    return ret.a[0][0];
}
qq real(qq n, qq m)
{
    
    qq a=n%m;
    if(a%2) return f(m-a);
    return((f(m)-f(m-a))%p+p)%p;
}
qq solve(qq n, qq m)
{
    
    qq t1=n/m;
    if(m%2)
    {
    
        if(!t1%2&&!t1%4) return f(n%m);
        if(!t1%2&&t1%4) return ((f(m)-f(n%m))%p+p)%p;
        if(t1%2&&!t1%4) return real(n,m);
        if(t1%2&&t1%4) return ((f(m)-real(n,m))%p+p)%p;
    }
    else
    {
    
        if(t1%2) return real(n,m);
        else return f(n%m);
    }
}
qq get_value(qq n, qq m)
{
    
    n+=2;
    qq a=solve(n,m);
    if(!a) return f(m)-1;
    else return a-1;
}
int main(){
    
    init();
    while(scanf("%lld%lld%lld",&n,&m,&p)!=EOF){
    
        qq ans=get_value(n,m);
        printf("%lld\n",ans);
    }
    return 0;
}

PREV-30 波动数列

简记:简单dp,时间复杂度O(n*n)

#include<bits/stdc++.h>
typedef long long LL;
using namespace std;
const int MOD = 1e8+7;

LL dp[1005][1005], tmp1, tmp2;

int main()
{
    
    LL n, s, a, b;
    cin>>n>>s>>a>>b;

    dp[1][(s%n+n)%n] = 1;
    for (int i = 1; i < n; i++)
    {
    
        tmp1 = b*(n-i)%n;
        tmp2 = a*(n-i)%n;
        for (int j = 0; j < n; j++)
        {
    
            dp[i+1][(j+tmp1)%n] = (dp[i+1][(j+tmp1)%n] + dp[i][j]) % MOD;
            dp[i+1][(j-tmp2+n)%n] = (dp[i+1][(j-tmp2+n)%n] + dp[i][j]) % MOD;
        }
    }
    cout<<dp[n][0]<<endl;
    return 0;
}

PREV-31 小朋友排队

简记:树状数组维护
设:
f(i)=a[i]左边严格大于a[i]的元素个数。
g(i)=a[i]右边严格小于a[i]的元素个数。
则:
a[i]的不高兴度为:1+2+…+f(i) + 1+2+…+g(i);

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100052;
typedef long long int qq;
int n;
struct Data{
    
    int val,id;
}a[maxn];
int p[maxn],c[maxn];
qq f(qq x){
    
    return (x+1)*x/2;
}
bool operator < (Data x, Data y){
    
    return x.val<y.val;
}
bool cmp_id(Data x, Data y){
    
    return x.id<y.id;
}
struct Bit_tree{
    
    int a[maxn],size;
    int lowbit(int x){
    
        return x&(-x);
    }
    void init(int x){
    
        size=x;
        for(int i=0;i<=size;i++){
    
            a[i]=0;
        }
    }
    void push(int pos, int val){
    
        while(pos<=size){
    
            a[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int ask(int pos){
    
        int ret=0;
        while(pos>0){
    
            ret+=a[pos];
            pos-=lowbit(pos);
        }
        return ret;
    }
    int ask(int l,int r){
    
        if(l>r)return 0;
        return ask(r)-ask(l-1);
    }
};
int main(){
    
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
    
        scanf("%d",&a[i].val);
        a[i].id=i;
    }
    ///离散化
    sort(a+1,a+1+n);
    int now=0;
    for(int i=1;i<=n;i++){
    
        if(i==1||a[i].val>a[i-1].val)now++;
        c[i]=now;
    }
    for(int i=1;i<=n;i++){
    
        a[i].val=c[i];
    }
    ///树状数组统计 p
    sort(a+1,a+1+n,cmp_id);
    memset(p,0,sizeof(p));
    Bit_tree tr;
    tr.init(now);
    for(int i=1;i<=n;i++){
    //a[i]左边比a[i]大的元素
        p[i]+=tr.ask(a[i].val+1,now);
        tr.push(a[i].val, 1);
    }
    tr.init(now);
    for(int i=n;i>0;i--){
    //a[i]右边比a[i]小的元素
        p[i]+=tr.ask(1,a[i].val-1);
        tr.push(a[i].val, 1);
    }
    qq ans=0;
    for(int i=1;i<=n;i++){
    
        ans+=f(p[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

PREV-32 分糖果

#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;

int a[1100]={
    0};
int n;
int num=0;

bool is_same()
{
    
	for(int i=0;i<n;i++)
	{
    
		if(a[0]!=a[i])return 0;
	}
	return 1;
}

void change()
{
    
	int b[1100]={
    0};
	for(int i=0;i<n;i++)
	{
    
		a[i]=a[i]/2;
		b[i+1]=a[i];
	}
	a[0]=a[0]+b[n];
	for(int i=1;i<n;i++)
	{
    
		a[i]=a[i]+b[i];
	}
}

void add()
{
    
	for(int i=0;i<n;i++)
	{
    
		if(a[i]%2==1)
		{
    
			num++;
			a[i]++;
		}
	}
}

int main()
{
    
	cin>>n;
	for(int i=0;i<n;i++)
	{
    
		cin>>a[i];
	}
	while(1)
	{
    
		if(is_same())break;
		change();
		add();
	}
	cout<<num;
	return 0;
}

PREV-33 兰顿蚂蚁

//简单模拟
#include<iostream>
#include<math.h>
#include<string.h>
using namespace std;
int l[5]={
    0,4,1,2,3};//左转数组 
int r[5]={
    0,2,3,4,1};//右转数组
int movex[5]={
    0,0,1,0,-1};
int movey[5]={
    0,-1,0,1,0}; 
bool color[150][150]={
    0};
int x,y;//起始坐标(x,y) 
int f;

void move()//在点(x,y)朝向f 
{
    
	if(color[y][x]==1)//如果是黑砖,右转90度,将该格改为白格,并向前移一格;
	{
    
		f=r[f];
		color[y][x]=0;
		x=x+movex[f];
		y=y+movey[f];
		
	}
	else//若蚂蚁在白格,左转90度,将该格改为黑格,并向前移一格。
	{
    
		f=l[f];
		color[y][x]=1;
		x=x+movex[f];
		y=y+movey[f];
		
	}
}

int main()
{
    
	int m,n;
	cin>>m>>n;//m行n列 
	for(int i=0;i<m;i++)
	{
    
		for(int j=0;j<n;j++)
		{
    
			scanf("%d",&color[i][j]);
		}
	}
	int k;char s;//上下左右分别用:U1,D3,L4,R2
	cin>>y>>x;
	scanf(" %c",&s);
	if(s=='U')f=1;
	if(s=='R')f=2;
	if(s=='D')f=3;
	if(s=='L')f=4;
	cin>>k;
	/*if(k==0)
	{
		cout<<y<<" "<<x;
		return 0;
	}
	x=x+movex[f];
	y=y+movey[f];*/
	for(int i=0;i<k;i++)
	{
    
		move();
	}
	cout<<y<<" "<<x;
	return 0;
}

PREV-34 矩阵翻硬币

简记:
思路:m*n的方格,ans = sqrt(m)*sqrt(n); 向下取整floor。大数据,二分求根号。
注:模拟十进制只能90分,压万进制可以满分

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2005;
const int bit = 10000;
struct Bnum{
    
    int a[maxn/4], len;
    void input(){
    
        memset(a,0,sizeof(a));
        char temp[maxn/2];
        scanf("%s",temp);
        len=strlen(temp);
        for(int i=0,j=len-1; j>=0; i++,j-=4){
    
            a[i]+=(temp[j]-'0');
            if(j-1>=0) a[i]+=(temp[j-1]-'0')*10;
            if(j-2>=0) a[i]+=(temp[j-2]-'0')*100;
            if(j-3>=0) a[i]+=(temp[j-3]-'0')*1000;
        }
        len=(len-1)/4+1;
    }
    void print(){
    
        for(int i=len-1;i>=0;i--){
    
            if(i==len-1)printf("%d",a[i]);
            else printf("%04d",a[i]);
        }
        printf("\n");
    }
}e,o;
void init(){
    
    memset(e.a,0,sizeof(e.a));
    e.len=1;    e.a[0]=1;
    memset(o.a,0,sizeof(o.a));
    o.len=1;
}
bool operator <= (Bnum x, Bnum y){
    
    if(x.len!=y.len) return x.len<y.len;
    int pos=x.len-1;
    while(pos>=0){
    
        if(x.a[pos]==y.a[pos]){
    
            pos--;continue;
        }
        return x.a[pos]<=y.a[pos];
    }
    return 1;
}
Bnum operator + (Bnum x, Bnum y){
    
    Bnum ret=o;
    ret.len=max(x.len, y.len);
    for(int i=0;i<ret.len;i++){
    
        ret.a[i]=x.a[i]+y.a[i];
    }
    for(int i=0;i<ret.len;i++){
    
        ret.a[i+1]+=ret.a[i]/bit;
        ret.a[i]%=bit;
    }
    if(ret.a[ret.len]!=0) ret.len++;
    return ret;
}
Bnum operator + (Bnum x, int y){
    //+1
    Bnum ret=x;
    ret.a[0]+=y;
    int p=0;
    for(int i=0;i<ret.len;i++){
    
        if(ret.a[i]/bit==0) break;
        ret.a[i+1]+=ret.a[i]/bit;
        ret.a[i]%=bit;
    }
    if(ret.a[ret.len]!=0)ret.len++;
    return ret;
}
Bnum operator - (Bnum x, int y){
    //-1
    Bnum ret=x;
    ret.a[0]-=y;
    for(int i=0;i<ret.len;i++){
    
        if(ret.a[i]>=0) break;
        ret.a[i+1]--;
        ret.a[i]+=bit;
    }
    if(ret.a[ret.len-1]==0)ret.len--;
    if(ret.len==0)ret.len++;
    return ret;
}
Bnum operator * (Bnum x, Bnum y){
    
    Bnum ret=o;
    for(int i=0;i<x.len;i++){
    
        for(int j=0;j<y.len;j++){
    
            ret.a[i+j]+=x.a[i]*y.a[j];
        }
    }
    ret.len=x.len+y.len-1;
    for(int i=0;i<ret.len;i++){
    
        ret.a[i+1]+=ret.a[i]/bit;
        ret.a[i]%=bit;
    }
    if(ret.a[ret.len]!=0) ret.len++;
    return ret;
}
Bnum operator / (Bnum x, int k){
    //除2下取整
    Bnum ret=x;
    for(int i=ret.len-1;i>=0;i--){
    
        if(i!=0) ret.a[i-1]+=bit*(ret.a[i]&1);
        ret.a[i]>>=1;
    }
    if(ret.a[ret.len-1]==0)ret.len--;
    return ret;
}
Bnum sqrt(Bnum x){
    
    Bnum l=e, r=x, mid;
    while(l<=r){
    
        mid=(l+r)/2;
        //printf("l=");   l.print();
        //printf("r=");   r.print();
        //printf("mid="); mid.print();
        if((mid*mid)<=x)l=mid+1;
        else r=mid-1;
    }
    return l-1;
}
void test(){
    
    Bnum x;
    long long int y;
    x.input();
    x.print();
    scanf("%lld",&y);
    printf("%lld\n",(long long int)sqrt(y));
    x=sqrt(x);
    x.print();
    x=x*x;
    x.print();
}
int main(){
    
    init();
    //while(1)test();
    Bnum x,y;
    x.input();
    y.input();
    Bnum ans=sqrt(x)*sqrt(y);
    ans.print();
    return 0;
}

PREV-35 正则问题

简记:
对于解决带括号的表达式求解问题,递归比较方便。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
char s[maxn];
int f(int &l, int r){
    
    int ret=0;
    while(l<r){
    
        //printf("%d %c %d\n",l,s[l],ret);
        if(s[l]=='x'){
    
            l++;ret++;
        }
        if(s[l]=='('){
    
            l++;
            ret+=f(l, r);
        }
        if(s[l]=='|'){
    
            l++;
            return max(ret, f(l, r));
        }
        if(s[l]==')'){
    
            l++;
            return ret;
        }
    }
    return ret;
}
int main(){
    
    scanf("%s",s);
    int x=0;
    printf("%d\n",f(x,strlen(s)));
    return 0;
}

PREV-36 包子凑数

简记:数论常识+打表找规律

#include<bits/stdc++.h>
using namespace std;
const int maxn = 105;
int a[maxn],n;
bool vis[maxn*maxn];
int main(){
    
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        scanf("%d",&a[i]);
    }
    int gcd=a[0];
    for(int i=1;i<n;i++){
    
        gcd=__gcd(gcd,a[i]);
    }
    if(gcd!=1){
    
        printf("INF\n");
    }
    else{
    
        vis[0]=1;
        int ans=0;
        for(int i=0;i<n;i++){
    
            for(int j=0;j<maxn*maxn;j++){
    
                if(j-a[i]>=0){
    
                    vis[j]=max( vis[j], vis[j-a[i]] );
                }
            }
        }
        bool first=1;
        for(int i=0;i<maxn*maxn;i++){
    
            if(!vis[i]){
    
                ans++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

PREV-37 分巧克力

简记:整体二分答案

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
typedef long long int qq;
struct choc{
    
    qq h,w;
}a[maxn];
int n;
qq k;
qq f(int x, choc p){
    
    return (p.h/x)*(p.w/x);
}
bool is_ok(int x){
    
    qq ans=0;
    for(int i=0;i<n;i++){
    
        ans+=f(x,a[i]);
    }
    return ans>=k;
}
int main(){
    
    scanf("%d%lld",&n,&k);
    for(int i=0;i<n;i++){
    
        scanf("%lld%lld",&a[i].w,&a[i].h);
    }
    int l=1,r=1e5;
    while(l<=r){
    
        int mid=(l+r)/2;
        if(is_ok(mid))l=mid+1;
        else r=mid-1;
    }
    printf("%d\n",l-1);
    return 0;
}

PREV-38 油漆面积

简记:本来是线段树扫描线的,暴力冲过去了

#include<bits/stdc++.h>
using namespace std;
bool book[10005][10005];
int main(int argc,char **argv)
{
    
	int cnt,sum=0;
	scanf("%d",&cnt);
	while(cnt--)
	{
    
		int x1,x2,y1,y2;
		scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
		int i,j;
		for(i=x1;i<x2;i++)
			for(j=y1;j<y2;j++)
			{
    
				if(book[i][j]==false)
				{
    
					book[i][j]=true;
					sum++;
				}
			}
	}
	printf("%d\n",sum);
	return 0;
}

PREV-39 日期问题

简记:模拟

#include<bits/stdc++.h>
using namespace std;
struct data{
    
    int y,m,d;
    void print(){
    
        printf("%d-%02d-%02d\n",y,m,d);
    }
}s,t;
int day[13]={
    0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_run(int x){
    
    if(x%100==0){
    
        return x%400==0;
    }
    return x%4==0;
}
data operator +(data x, int ppp){
    //+1
    data ret=x;
    ret.d++;
    if(ret.d> day[ret.m]+(ret.m==2&&is_run(ret.y))){
    
        ret.d=1;
        ret.m++;
        if(ret.m==13){
    
            ret.m=1;
            ret.y++;
        }
    }
    return ret;
}
bool operator == (data l, data r){
    
    return l.y==r.y&&l.m==r.m&&l.d==r.d;
}
bool operator <= (data l, data r){
    
    if(l.y!=r.y){
    
        return l.y<r.y;
    }
    if(l.m!=r.m){
    
        return l.m<r.m;
    }
    return l.d<=r.d;
}
void init(){
    
    s.y=1960;   s.m=1;   s.d=1;
    t.y=2059;   t.m=12;   t.d=31;
}
int a,b,c;
bool is_ok(data x){
    
    if(x.y%100==a&&x.m==b&&x.d==c)return 1;
    if(x.y%100==c&&x.m==a&&x.d==b)return 1;
    if(x.y%100==c&&x.m==b&&x.d==a)return 1;
    return 0;
}
int main(){
    
    init();
    scanf("%d/%d/%d",&a,&b,&c);
    for(data i=s;i<=t;i=i+1){
    
        if(is_ok(i)) i.print();
    }
    return 0;
}

PREV-40 k倍区间

简记:简单维护思想

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
typedef long long int qq;
int n,a[maxn],c[maxn],s[maxn],k;
int main(){
    
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
    
        scanf("%d",&a[i]);
        s[i]=(s[i-1]+a[i])%k;
        c[s[i]]++;
    }
    qq ans=0;
    for(int i=1;i<=n;i++){
    
        ans+=c[s[i-1]];
        c[s[i]]--;
    }
    printf("%lld\n",ans);
    return 0;
}

PREV-41 Excel地址

简记:进制知识

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
int a[100];
int main(){
    
    qq n;
    while(scanf("%lld",&n)!=EOF){
    
        int cnt=0;
        while(n){
    
            if(n%26==0){
    
                a[cnt++]=26;
                n/=26;
                n--;
            }
            else{
    
                a[cnt++]=n%26;
                n/=26;
            }
        }
        for(int i=cnt-1;i>=0;i--){
    
            char c='A'+a[i]-1;
            printf("%c",c);
        }
        printf("\n");
    }
    return 0;
}

PREV-42 九宫幻方

简记:dfs暴力搜索即可

#include<bits/stdc++.h>
using namespace std;
int a[3][3],ans[3][3];
int vis[10],num=0;
bool is_ok(){
    
    int e=(1+9)*9/2;
    e/=3;
    for(int i=0;i<3;i++){
    
        int s1=0,s2=0;
        for(int j=0;j<3;j++){
    
            s1+=a[i][j];
            s2+=a[j][i];
        }
        if(s1!=e||s2!=e)return 0;
    }
    if(a[0][0]+a[1][1]+a[2][2]!=e)return 0;
    if(a[0][2]+a[1][1]+a[2][0]!=e)return 0;
    return 1;
}
void out(){
    
    for(int i=0;i<3;i++){
    
        for(int j=0;j<3;j++){
    
            printf("%d ",a[i][j]);
        }
        printf("\n");
    }
    printf("-----\n");
}
void dfs(int dep){
    

    if(num==2)return;
    if(dep==9){
    
        //out();
        if(is_ok()){
    
            num++;
            for(int i=0;i<3;i++)for(int j=0;j<3;j++){
    
                ans[i][j]=a[i][j];
            }
        }
        return ;
    }
    int x=dep%3, y=dep/3;
    //printf("dep=%d (%d,%d)=%d \n",dep,x,y,a[x][y]);
    if(a[x][y]!=0)dfs(dep+1);
    else{
    
        for(int i=1;i<=9;i++){
    
            if(vis[i])continue;
            a[x][y]=i;
            vis[i]=1;
            dfs(dep+1);
            a[x][y]=0;
            vis[i]=0;
        }
    }
}
int main(){
    
    memset(vis,0,sizeof(vis));
    for(int i=0;i<3;i++){
    
        for(int j=0;j<3;j++){
    
            scanf("%d",&a[i][j]);
            vis[a[i][j]]++;
        }
    }
    dfs(0);
    if(num==1){
    
        for(int i=0;i<9;i++){
    
            printf("%d",ans[i/3][i%3]);
            if(i%3==2) printf("\n");
            else printf(" ");
        }
    }
    else {
    
        printf("Too Many\n");
    }
    return 0;
}

PREV-44 青蛙跳杯子

简记:bfs

#include<bits/stdc++.h>
using namespace std;
const int bas = 15;
int mov[6]= {
    -3, -2, -1, 1, 2, 3 }, len;
struct state{
    
    int a[bas],pos,step,hast=-1;
    int hash(){
    
        //if(hast!=-1)return hast;
        int ret=0;
        for(int i=0;i<len;i++){
    
            ret=ret*3+a[i];
            //printf("ret=%d\n",ret);
        }
        return ret;
    }
    void input(char *s, int n){
    
        for(int i=0;i<n;i++){
    
            if(s[i]=='*'){
    
                a[i]=0;pos=i;
            }
            if(s[i]=='W') a[i]=1;
            if(s[i]=='B') a[i]=2;
        }
    }
    void print(){
    
        printf("%d  ",step);
        for(int i=0;i<len;i++){
    
            printf("%d",a[i]);
        }
        printf("\n");
    }
};
bool vis[15000000];
queue<state>q;
int bfs(state s, state t, int n){
    
    len=n;
    memset(vis,0,sizeof(vis));
    vis[s.hash()]=1;
    s.step=0;
    q.push(s);
    int e=t.hash();
    while(!q.empty()){
    
        //q.front().print();
        if(q.front().hash()==t.hash())return q.front().step;
        state now=q.front();
        now.step++;
        for(int i=0;i<6;i++){
    
            if(now.pos+mov[i]<0 || now.pos+mov[i]>=len)continue;
            int t= now.a[now.pos];
            now.a[now.pos]=now.a[now.pos+mov[i]];
            now.a[now.pos+mov[i]]=t;
            now.pos+=mov[i];
            now.hast=-1;

            int add=now.hash();
            if(vis[add]){
    
                t= now.a[now.pos];
                now.a[now.pos]=now.a[now.pos-mov[i]];
                now.a[now.pos-mov[i]]=t;
                now.pos-=mov[i];
                now.hast=-1;
                continue;
            }
            vis[add]=1;
            q.push(now);
            //printf("step=%d\n",now.step);
            //printf("@1 ");now.print();

            t= now.a[now.pos];
            now.a[now.pos]=now.a[now.pos-mov[i]];
            now.a[now.pos-mov[i]]=t;
            now.pos-=mov[i];
            now.hast=-1;

            //printf("@2 ");now.print();
        }
        q.pop();
    }
}
int main(){
    
    //printf("%lf\n",pow(3,15));
    char temp[100];
    state s,t;
    scanf("%s",temp);
    s.input(temp,strlen(temp));
    scanf("%s",temp);
    t.input(temp,strlen(temp));
    printf("%d\n",bfs(s,t,strlen(temp)));
    return 0;
}

PREV-49 发现环

简记:两次dfs找环即可,基环树。

#include<bits/stdc++.h>
using namespace std;
#define maxn 100052
int vis[maxn];
int a[maxn],n,cnt=0,xcx=0,flag=0;
vector<int>u[maxn];
void dfs(int x, int fa){
    
    if(xcx!=0)return;
    vis[x]=1;
    for(int i=0;i<u[x].size();i++){
    
        if(u[x][i]==fa)continue;
        if(vis[u[x][i]]){
    
            xcx=u[x][i];
            vis[x]=0;
            return ;
        }
        dfs(u[x][i],x);
    }
    vis[x]=0;
}
void dfs2(int x,int fa){
    
    if(flag==1)return;
    for(int i=0;i<u[x].size();i++){
    
        if(u[x][i]==fa)continue;
        if(u[x][i]==xcx){
    
            flag=1;
            a[cnt++]=x;
            return;
        }
        //printf("x=%d %d\n",x,u[x][i]);
        dfs2(u[x][i],x);
        if(flag==1){
    
            a[cnt++]=x;
            return;
        }
    }

    vis[x]=0;
}
int main(){
    
    scanf("%d",&n);
    for(int i=0;i<n;i++){
    
        int t1,t2;
        scanf("%d%d",&t1,&t2);
        u[t1].push_back(t2);
        u[t2].push_back(t1);
    }
    dfs(1,0);
    memset(vis,0,sizeof(vis));
    //printf("%d\n",xcx);
    dfs2(xcx,0);
    /*for(int i=1;i<=n;i++){
        if(vis[i])a[cnt++]=i;
    }*/
    sort(a,a+cnt);
    for(int i=0;i<cnt;i++){
    
        if(i!=0)printf(" ");
        printf("%d",a[i]);
    }
    printf("\n");
    return 0;
}


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36306833/article/details/87866871

智能推荐

可狱可囚的爬虫系列课程 07:BeautifulSoup4(bs4)库的使用_beautifulsoup4库 获取br-程序员宅基地

文章浏览阅读1.5k次,点赞21次,收藏18次。BeautifulSoup4 属于 BeautifulSoup 系列的第四代版本,BeautifulSoup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库,这个库能够实现树文档的导航、查找,从而帮助我们提取到网页中所需要的数据。。如果忘记了在哪里安装,请回看 Requests 模块第一篇文章。安装好以后,我们围绕数据提取这个话题对 BeautifulSoup4 进行剖析。"""# 问题一:使用标签选择器获取源代码中所有的 p 标签。_beautifulsoup4库 获取br

rpm包及作用_cannot install both libpng-2:1.5.13-8.el7.x86_64 a-程序员宅基地

文章浏览阅读1.9k次。基于Red Hat Enterprise Linux Server release 7.4 (Maipo)最小化安装将会慢慢补齐每个包的作用:1 bash-completion-2.1-6.el7.noarch https://cbs.centos.org/koji/rpminfo?rpmID=4260 2 grubby-8.28-23.el7.x86_64 ..._cannot install both libpng-2:1.5.13-8.el7.x86_64 and libpng-2:1.6.37-1.ky10.

vxworks的RTP学习_vxworks rtp-程序员宅基地

文章浏览阅读2.1k次。这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Ma..._vxworks rtp

用户层与驱动通信-程序员宅基地

文章浏览阅读185次。以进行加法和减法为例,用户层将要进行的操作码和参数,返回缓冲发给驱动,驱动进行处理并将结果写到返回缓冲中driver.c//_stdcall#include<ntddk.h>#include<ntstrsafe.h>#pragma code_seg("INT")#define SynLinkName L"\\??\\freesec_tx..._pirpstack->majorfunction

Android Framework 分析-程序员宅基地

文章浏览阅读91次。http://raymond1860.spaces.live.com/Blog/cns!BF47B6FD104579C9!797.entry1.目录树/framework/base/api/framework/base/awt/framework/base/build/framework/base/camera关 于camera的HAL接口库。最终生成native共享库l..._android framework cmds 开发

springboot+mysql互联网互联网美食分享平台源码53102-程序员宅基地

文章浏览阅读82次。免费领取项目源码,请关注●点赞收藏并私信博主,谢谢-、互联网美食分享平台采用Java技术,Mysql数据库存储数据,基于Springboot框架开发。系统采用了模块化设计方法,根据用户的需求开发功能模块,方便了程序扩展维护,以便后期的更新。整个开发过程首先对系统进行需求分析,得出系统主要功能模块。接着对系统进行总体设计和详细设计。最后对系统进行了功能测试,并对测试结果进行了分析总结,得出系统的不足及需要改进的地方,为以后的系统维护提供了方便,同时也为以后开发类似系统提供了借鉴和帮助。

随便推点

E - Mafia CodeForces - 348A 【二分】_348a二分-程序员宅基地

文章浏览阅读317次。E - Mafia CodeForces - 348A 【二分】One day n friends gathered together to play “Mafia”. During each round of the game some player must be the supervisor and other n - 1 people take part in the game. Fo..._348a二分

四元数和旋转矩阵_四元数 旋转矩阵-程序员宅基地

文章浏览阅读1.6w次。四元数和旋转矩阵Quaternion(四元数)Quaternion 的定义四元数一般定义如下: q=w+xi+yj+zk其中 w,x,y,z是实数。同时,有: i*i=-1 j*j=-1 k*k=-1四元数也可以表示为: q=[w,v]其中v=(x,y,z)是矢量,w是标量,虽然v是矢量,但不能简_四元数 旋转矩阵

WebComponents.exe未安装的解决办法-程序员宅基地

文章浏览阅读5.8w次,点赞6次,收藏3次。很多人在使用海康威视的开发包的时候,都会遇到下面几个问题在安装WebComponents.exe之后 浏览器在运行的时候提示WebComponents.exe为安装 或者是WebComponents.exe不是最新版本开发包提供的版本如下,浏览器自动安装的版本为3.0.5.34这2个版本都是是可以使用的 ,而且不需要更新那么问题就在浏览器了_webcomponents.exe

集成测试与系统测试_集成测试是系统测试吗-程序员宅基地

文章浏览阅读1.4w次,点赞5次,收藏42次。 集成测试与系统测试_集成测试是系统测试吗

Jenkins中文官网地址_jenkins官网-程序员宅基地

文章浏览阅读792次,点赞9次,收藏8次。Jenkins 是一个开源自动化服务器。Jenkins 用户手册。_jenkins官网

nginx 网页匹配跳转(rewrite、location)_nginx location直接指向某个网页-程序员宅基地

文章浏览阅读1.7k次,点赞29次,收藏23次。location,rewrite基于:域名、客户端ip、旧域名、参数匹配,跳转_nginx location直接指向某个网页

推荐文章

热门文章

相关标签