蓝桥杯题库题解合集(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大数查询

#include<bits/stdc++.h>
using namespace std;
#define maxn 10052
int a[maxn],b[maxn];
bool cmp(int x,int y){
    return x>y;
}
int main(){
    int n,m;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    scanf("%d",&m);
    while(m--){
            int l,r,k;
        scanf("%d%d%d",&l,&r,&k);
        for(int i=l;i<=r;i++){
            b[i]=a[i];
        }
        sort(b+l,b+r+1,cmp);
        printf("%d\n",b[l+k-1]);
    }
    return 0;
}

ALGO-2 最大最小公倍数

题目大意:
1~n中选3个数,lcm最大
简记:
没想到太好的贪心办法,就是只找区间[n-100,n]之间的数字,选一个最大的组合。

#include<bits/stdc++.h>
using namespace std;
typedef long long qq ;
qq lcm(qq x, qq y){
    return x*y/__gcd(x,y);
}
qq lcm(int x, int y, int z){
    return lcm(x,lcm(y,z));
}
struct Node {
    int a[3] ;
    Node () {} ;
    Node ( int x , int y , int z ) {
        a[0] = x ;
        a[1] = y ;
        a[2] = z ;
    }
    qq val () {
        return lcm ( a[0], a[1], a[2] ) ;
    }
    void print() {
        sort ( a , a+3 ) ;
        printf( "%d %d %d  " , a[0], a[1], a[2] );
    }
    void print_dis( int n ) {
        printf( "%d %d %d \n" ,a[1]-a[0], a[2]-a[1], n-a[2] ) ;
    }
};

void test(){
    for ( int n=5; n<1000; n++ ) {
        n=95152;
        int ans = -1;
        Node best ;
        for( int i=1; i<=n; i++ ) { for( int j=i+1; j<=n; j++ ) { for ( int k=j+1; k<=n; k++ ) {
            if ( ans < lcm ( i, j, k ) ) {
                best = Node( i, j, k ) ;
            }
        } } }
        printf("%d : ", n );
        best.print();
        best.print_dis(n);
    }
}
int main(){
    //test();
    long long int n;
    scanf("%lld",&n);
    qq ans = -1;
    for( int i=n; i>max((qq)0,n-100); i-- ) {
        for( int j=i-1; j>max(0,i-100); j-- ) {
            for( int k=j-1; k>max(0,j-100); k-- ) {
                ans = max( ans, lcm( i, j, k ) ) ;
            }
        }
    }
    printf( "%lld\n" , ans );
    return 0;
}

ALGO-3 K好数

题目大意:
找出有多少个 L L 位的 K K 进制数,他们任意相邻位数字都不相同。
简记:
状态描述:
d p ( i , j ) dp(i,j) 表示共 i i 位,最后一位是 j j 的满足要求的数字序列个数
状态转移方程:
d p ( i , j ) = p = 0 k 1 d p ( i 1 , p ) ( a b s ( j p ) ! = 1 ) ; dp(i,j) = \sum_{p=0}^{k-1}{dp(i-1,p)}(abs(j-p)!=1);
初始状态:
d p ( 1 , 1   K 1 ) = 1 ; dp(1,1~K-1) = 1;
d p ( 1 , 0 ) = 0 ; dp(1,0) = 0;

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
const qq MOD = 1000000007;
inline qq mod( qq x ) { return (x%MOD); }
inline qq mof( qq x ) { return mod(mod(x)+MOD); }
const int maxn = 105;
qq dp[maxn][maxn];
int main()
{
    int k , l ;
    while( scanf( "%d%d" , &k, &l) != EOF ) {
        dp[1][0] = 0;
        for ( int i=1; i<maxn; i++ ) {
            dp[1][i] = 1;
        }
        for ( int i=2; i<=l; i++ ) {
            memset ( dp[i], 0, sizeof(dp[i]) );
            for( int j=0; j<k; j++ ) {
                for( int p=0; p<k; p++ ) {
                    if ( abs(j-p) == 1 ) continue;
                    dp[i][j] = mod( dp[i][j] + dp[i-1][p] );
                }
            }
        }
        qq ans = 0;
        for ( int i=0; i<k; i++ ) {
            //printf("%lld ",dp[l][i]);
            ans = mod( ans+ dp[l][i] ) ;
        }
        printf( "%lld\n" , mof(ans) );
    }
    return 0;
}

ALGO-4 结点选择

题目大意:
一棵点权树选出若干个结点,保证任意两个结点都不直接相连,求最大能得到的权值。
简记:
状态描述:
$dp(i,0) 表示以 i 号结点为根的子树,不选 i$号结点,能得到的最大值
$dp(i,1) 表示以 i 号结点为根的子树,选 i$号结点,能得到的最大值
状态转移方程:
d p ( i , 0 ) = m a x ( d p ( s o n ( i , j ) , 0 ) , d p ( s o n ( i , j ) , 1 ) ) ; dp(i,0) = \sum{ max(dp(son(i,j),0),dp(son(i,j),1) ) };
d p ( i , 1 ) = d p ( s o n ( i , j ) , 0 ) + v i ; dp(i,1) = \sum{ dp(son(i,j),0) } + v_i;
初始状态:
d p ( l e v e l , 0 ) = 0 ; dp(level,0) = 0;
d p ( l e v e l , 1 ) = v l e v e l ; dp(level,1) = v_{level};

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100052;
vector < int > u[maxn] ;
int v[maxn], n, dp[maxn][2] ;
void dfs ( int x , int fa ) {
    dp[x][0] = 0 ;
    dp[x][1] = v[x] ;
    for ( int i=0; i<u[x].size(); i++ ) {
        if ( u[x][i] == fa ) continue ;
        dfs ( u[x][i], x ) ;
        dp[x][1] += dp[u[x][i]][0] ;
        dp[x][0] += max ( dp[u[x][i]][0] , dp[u[x][i]][1] ) ;
    }
}
int main()
{
    scanf( "%d" , &n ) ;
    for( int i=1; i<=n; i++ ) {
        scanf( "%d", &v[i] ) ;
    }
    for( int i=1; i<n; i++ ) {
        int s , t ;
        scanf( "%d%d" , &s, &t );
        u[s].push_back( t ) ;
        u[t].push_back( s ) ;
    }
    memset ( dp , 0 ,sizeof(dp) ) ;
    dfs( 1 , -1 ) ;
    int ans = -1;
    for ( int i=1 ;i<=n ;i++ ) {
        ans = max( ans , max ( dp[i][0], dp[i][1] ) );
    }
    printf( "%d\n" , ans ) ;
    return 0;
}

ALGO-5 最短路

简记:
最短路模板题,注意负边权,用堆优化的 D i j k s t r a Dijkstra 就好。

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq ;
const qq INF = 0x3f3f3f3f;
const int maxn_edge = 200052 ;
const int maxn_node = 20052 ;
struct HeapNode{
    HeapNode(int u,qq d):u(u),dist(d){}
	int u;
	qq dist;
	bool operator < (const HeapNode& h) const {
		return dist>h.dist;
	}
};
struct Edge {
    int s, to ;
    qq w ;
    Edge () {} ;
    Edge ( int s , int to , qq w ) {
        this->s = s;
        this->to = to;
        this->w = w;
    } ;
};
vector < Edge > edge ;
vector < int > u[maxn_node] ;
qq dis[maxn_node] ;
int n , m ;
bool vis[maxn_node];

void AddEdge ( int s , int t , qq w ) {
    edge.push_back( Edge (s,t,w) ) ;
    u[s].push_back( edge.size()-1 ) ;
}
void Init () {
    for ( int i=0; i<maxn_node; i++ ) {
        dis[i] = INF * INF ;
        vis[i] = false ;
    }
}
void Dijkstra ( int s ) {
    Init();
    priority_queue < HeapNode > Q;
    dis[s]= 0;
    Q.push( HeapNode(s,0) );
    while ( Q.empty() == false ) {
        int now = Q.top().u;
        Q.pop();
        if ( vis[now] == true ) continue;
        vis[now] = true;
        for( int i=0; i<u[now].size(); i++ ) {
            Edge &e = edge[u[now][i]] ;
            if( dis[e.to] > dis[now]+e.w ){
                dis[e.to] = dis[now]+e.w ;
                Q.push( HeapNode(e.to, dis[e.to]) );
            }
        }
    }
}
int main()
{
    scanf( "%d%d" , &n, &m ) ;
    for( int i=0; i<m; i++ ) {
        int s , t ;
        qq w ;
        scanf( "%d%d%lld" , &s, &t, &w ) ;
        AddEdge ( s, t, w ) ;
    }
    Dijkstra ( 1 ) ;
    for ( int i= 2; i<=n; i++ ) {
        printf( "%d\n" , dis[i] ) ;
    }
    return 0;
}

ALGO-6 安慰奶牛

ALGO-7 逆序对

ALGO-8 操作格子

ALGO-42 送分啦

#include<bits/stdc++.h>
using namespace std;
int main(){
    printf("yes\n");
    return 0;
}

ALGO-48 关联矩阵

#include<bits/stdc++.h>
using namespace std;
#define maxn 1052
int out[maxn][maxn], n, m ;
int main(){
    scanf("%d%d",&n,&m);
    memset(out,0,sizeof(out));
    for(int i=0;i<m;i++) {
        int ss,tt;
        scanf("%d%d",&ss,&tt);
        out[ss][i] = 1 ;
        out[tt][i] = -1 ;
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<m;j++){
            printf("%d",out[i][j]);
            if(j==m-1) printf("\n");
            else printf(" ");
        }
    }
    return 0;
}

ALGO-49 寻找数组中最大值

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

    return 0;
}

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

简记:线性素数筛就好了

#include<bits/stdc++.h>
using namespace std;
typedef long long int qq;
const int maxn = 5000052;
#define MOD (50000)
#define mod(x) ((x)%MOD)
bool vis[maxn];
int prime[maxn];
void InitPrime () {
    memset ( vis, 0, sizeof(vis) ) ;
    int cnt = 1 ;
    for ( int i=2; i<maxn;i ++ ) {
        if ( vis[i] == false ) {
            prime[cnt++] = i;
            //continue;
        }
        for ( int j=1; j<cnt; j++ ) {
            if ( (qq)i*prime[j]>=maxn ) break;
            vis[ i*prime[j] ] = true ;
            if ( i%prime[j] == 0 ) break;
        }
    }
}
int main(){
    InitPrime();
    int ans=1 ,n ;
    scanf( "%d" ,&n ) ;
    for( int i=1; i<=n; i++ ) {
        ans = mod( (qq)ans*prime[i] ) ;
    }
    printf( "%d\n" , ans ) ;
    return 0;
}

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

简记:
n小于8可以枚举全排列找最优,另想了一个贪心做法(对,就是大家都会选择的做法),随机生成数据对拍测试一下正确性,发现是应该是对的。

#include<bits/stdc++.h>
using namespace std;
#define INF ( 0x3f3f3f3f )
int T, n, a[10], b[10], ans ;
bool vis[10] ;
void dfs( int x , int val ) {
    if ( x == n ) {
        ans = min( ans , val ) ;
        return ;
    }
    for( int i=0; i<n; i++ ) {
        if ( vis[i] == true ) continue ;
        vis[i] = true ;
        dfs( x+1 , val + a[i]*b[x] );
        vis[i] = false ;
    }
}
void Test () {
    scanf( "%d" , &T ) ;
    while ( T-- ) {
        int n = rand()%10 +1 ;
        for( int i=0; i<n; i++ ) {
            a[i] = rand()%100-50;
        }
        for( int i=0; i<n; i++ ) {
            a[i] = rand()%100-50;
        }
        ans = INF;
        dfs ( 0 , 0 ) ;
        int ans2 = 0;
        sort( a, a+n ) ;
        sort( b, b+n ) ;
        for( int i=0; i<n; i++ ) {
            ans2 += a[i]*b[n-i-1];
        }
        if( ans != ans2 ) {
            printf( "error\n" ) ;
        }
        if ( T%1000 == 0 ) printf( "%d\n" , T ) ;
    }
}
int main(){
    //Test();
    scanf( "%d" , &T ) ;
    while ( T-- ) {
        scanf( "%d" , &n ) ;
        for( int i=0; i<n; i++ ) {
            scanf( "%d" ,&a[i] ) ;
        }
        for( int i=0; i<n; i++ ) {
            scanf( "%d" ,&b[i] ) ;
        }
        ans = INF;
        dfs ( 0 , 0 ) ;
        printf( "%d\n" , ans ) ;
    }
    return 0;
}

ALGO-79 删除数组零元素

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000052
int n, a[maxn] ;
int main()
{
    scanf( "%d" , &n );
    int m = 0;
    for(int i=0;i<n;i++) {
        scanf("%d",&a[i]);
        if(a[i]!=0) m++;
    }
    printf("%d\n",m);
    bool first = true ;
    for(int i=0;i<n;i++){
        if(a[i]==0)continue ;
        if( first == false ) printf(" ");
        first = false;
        printf("%d",a[i]);
    }
    return 0;
}

ALGO-81 动态数组使用

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000052
int n;
int main()
{
    scanf( "%d" , &n );
    long long int sum = 0 ;
    int now ;
    for(int i=0;i<n;i++) {
        scanf("%d",&now);
        sum += now;
    }
    printf("%lld %lld\n",sum,sum/n);
    return 0;
}

ALGO-84 大小写转换

#include<bits/stdc++.h>
using namespace std;
int main()
{
    char c ;
    while(scanf("%c",&c)!=EOF){
        if( c>='a'&&c<='z' ) {
            printf("%c",c-'a'+'A');
        }
        else if( c>='A'&&c<='Z' ) {
            printf("%c",c-'A'+'a');
        }
        else printf("%c",c);
    }
    return 0;
}

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) 表示在点 ( i , j ) (i,j) ,当前手里有 k k 个物品,最大的为 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);
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 ) : 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);
3.初始状态:
d p ( 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;
一个坑点:有的礼物价值会为 0 0 ,转移过程会出问题,解决办法: 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;
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};
样例没过,但是满分了,最后一点很复杂的分类讨论不想看了~

#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;
}


发布了227 篇原创文章 · 获赞 142 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_36306833/article/details/90146753