牛客小白月赛36

B-最短串

题目

牛客小白月赛36_第1张图片
草率了,没想到可以暴力枚举,而且3ms就过了。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e4+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 99824353;
typedef long long ll;
int ans;
void solve(char *s1,char *s2)
{
    int n=strlen(s1),m=strlen(s2);
    for(int i=0;i<n;i++){
        bool is=1;
        for(int j=0;j<m&&i+j<n;j++){
            if(s1[i+j]=='?'||s2[j]=='?'||s1[i+j]==s2[j])continue;
            is=0;
            break;
        }
        if(is){
            ans=min(ans,max(n,i+m));
            break;
        }
    }
}
int main()
{
    char s1[M],s2[M];
    scanf("%s%s",s1,s2);
    int n=strlen(s1),m=strlen(s2);
    ans=n+m;
    solve(s1,s2);
    solve(s2,s1);
    printf("%d\n",ans);
    return 0;
}

C-杨辉三角

题目
牛客小白月赛36_第2张图片
杨辉三角第n行第i个元素为 C n − 1 i − 1 , 由 二 项 式 定 理 有 ( 1 + x ) n = ∑ C n i ∗ x i , 对 两 边 求 导 , n ( 1 + x ) n − 1 = ∑ i ∗ C n i ∗ x i − 1 , 继 续 求 导 , n ( n − 1 ) ( 1 + x ) n − 2 = ∑ ( i 2 − i ) ∗ C n i ∗ x i − 2 , 令 x = 1 , n ( n − 1 ) ∗ 2 n − 2 = ∑ i 2 C n i − ∑ i C n i , 易 证 ∑ C n i = n ( n − 1 ) ∗ 2 n − 3 C_{n-1}^{i-1},由二项式定理有(1+x)^n=\sum{C_{n}^{i}*x^i},对两边求导,n(1+x)^{n-1}=\sum{i*C_n^i*x^{i-1}},继续求导,n(n-1)(1+x)^{n-2}=\sum{(i^2-i)*C_n^i*x^{i-2}},令x=1,n(n-1)*2^{n-2}=\sum{i^2C_n^i}-\sum{iC_n^i},易证\sum{C_n^i}=n(n-1)*2^{n-3} Cn1i1,(1+x)n=Cnixi,,n(1+x)n1=iCnixi1,n(n1)(1+x)n2=(i2i)Cnixi2,x=1n(n1)2n2=i2CniiCni,Cni=n(n1)2n3,用快速幂求解即可。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e4+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 99824353;
typedef long long ll;
ll power(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    ll n;
    scanf("%lld",&n);
    if(n>=3)
    printf("%lld\n",(n%mod*((n-1)%mod))%mod*power(2,n-3)%mod);
    else{
        printf("%lld\n",n-1);
    }
    return 0;
}

D-哥三好

题目

牛客小白月赛36_第3张图片
可以用三维dp来写,但是a,b,c有1e4,不能直接开这么大的数组,因为包夜价格为100 * 3,150 * 3,250 *3.
显然最大公约数为150,除以公约数后变成2,3,5,a,b,c也要除以150.这样就能开了。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e2 + 7;
const int M = 1e3+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
typedef long long ll;
int dp[N][N][N];
int cost[3]={2,3,5};
void init()
{
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                dp[i][j][k]=1;
}
int main()
{
    init();
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    a/=150,b/=150,c/=150;
    for(int i=0;i<=a;i++){
        for(int j=0;j<=b;j++){
            for(int k=0;k<=c;k++){
                for(int m=0;m<3;m++){
                    if(i>=cost[m])dp[i][j][k]=(dp[i][j][k]+dp[i-cost[m]][j][k])%mod;
                    if(j>=cost[m])dp[i][j][k]=(dp[i][j][k]+dp[i][j-cost[m]][k])%mod;
                    if(k>=cost[m])dp[i][j][k]=(dp[i][j][k]+dp[i][j][k-cost[m]])%mod;
                }
            }
        }
    }
    printf("%d\n",dp[a][b][c]%mod);
    return 0;
}

E-皇城PK

题目
牛客小白月赛36_第4张图片
要可能成为冠军就不能输过,所以入度为0。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e4+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
int in[N];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i, 1, m){
        int u,v;
        scanf("%d%d",&u,&v);
        in[v]++;
    }
    int ans=0;
    rep(i, 1, n)if(!in[i])ans++;
    printf("%d\n",ans);
    return 0;
}

F-象棋

题目
牛客小白月赛36_第5张图片
显然每列最后只能剩下两个,然后这两个可以到后面的列里,重复让每列剩下两个然后到后面列,直到没有第三列可以攻击,即只剩2列,而每列又只有2个,所以最少4个,特判一下行和列只有1的情况

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e4+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 998244353;
typedef long long ll;
int main()
{
    int t;
    scanf("%d",&t);
    ll n,m;
    while(t--){
        scanf("%lld%lld",&n,&m);
        if(n==1&&m==1)puts("1");
        else if(n>=2&&m>=2)puts("4");
        else puts("2");
        
    }
    return 0;
}

H-卷王之王

题目

牛客小白月赛36_第6张图片
线段树模板题(
刚开始觉得要区间线段树,然后感觉麻烦没写,然后大佬说单点就能过,然后就真的过了

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e3+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 99824353;
typedef long long ll;

ll tree[N<<2];
ll a[N];
void pushup(int j)
{
    tree[j]=min(tree[j<<1],tree[j<<1|1]);
}
void build(int node,int l,int r)
{
    if(l==r){
        tree[node]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    pushup(node);
}
void update(int node,int l,int r,int val)
{
    if(tree[node]>val)return;
    if(l==r){
        tree[node]+=val;
        return;
    }
    int mid=(l+r)>>1;
    update(node<<1,l,mid,val);
    update(node<<1|1,mid+1,r,val);
    pushup(node);
}
ll query(int node,int l,int r,int pos)
{
    if(l==r)return tree[node];
    int mid=(l+r)>>1;
    if(pos<=mid)return query(node<<1,l,mid,pos);
    else return query(node<<1|1,mid+1,r,pos);
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,1,n)scanf("%lld",&a[i]);
    build(1,1,n);
    rep(i,1,m){
        ll x;
        scanf("%lld",&x);
        if(!x)continue;
        update(1,1,n,x);
    }
    rep(i,1,n){
        printf("%lld ", query(1,1,n,i));
    }
    puts("");
    return 0;
}

I-四面楚歌

题目

牛客小白月赛36_第7张图片
就硬搜索,搜索的时候把遇到的0都标记然后计数,只要起点0能突围,那么遇到的0也都能突围,就这我还wa了7发。

牛客小白月赛36_第8张图片

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e3+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 99824353;
typedef long long ll;
char ch[M][M];
bool flag=0;
int cnt=0;
bool vis[M][M];
int n,m;
bool is[M][M];
void dfs(int x,int y)
{
    if(is[x][y])return;
    is[x][y]=1;
    if(x==0||x==n-1||y==0||y==m-1){
        
        is[x][y]=0;
        flag=1;
       // printf("$\n");
        if(ch[x][y]=='0'&&!vis[x][y])cnt++;
        vis[x][y]=1;
        return ;
    }
    if(ch[x+1][y]!='1'&&!is[x+1][y])
        dfs(x+1,y);
    if(ch[x][y+1]!='1'&&!is[x][y+1])
        dfs(x,y+1);
    if(ch[x-1][y]!='1'&&!is[x-1][y])
        dfs(x-1,y);
    if(ch[x][y-1]!='1'&&!is[x][y-1])
        dfs(x,y-1);
    if(ch[x][y]=='0'){
        cnt++;
        //printf("#\n");
        vis[x][y]=1;
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,0,n-1){
        scanf("%s",ch[i]);
    }
    int ans=0;
    rep(i,0,n-1){
        rep(j, 0, m-1){
            if(ch[i][j]=='0'){
                cnt=0;
                dfs(i,j);
                if(flag==1){
                    flag=0;
                    //memset(is,0, sizeof is);
                    ans+=cnt;
                    //printf("%d\n",cnt);
                }
            }
        }
        //puts("");
    }
    //printf("%c",ch[2][1]);
    printf("%d\n",ans);
    return 0;
}

我是傻逼,都想到连通的0一起计数,还各种标记然后每个连通块dfs,其实可以从(0,0)出发,这样所有可以突围的0都在一个连通块,虽然时间上没差,但是好写多了。
在这里插入图片描述
代码巨短。

#include <iostream>
#include <cstring>
#include <cmath>
#include <bitset>
#include <queue>
#include <vector>
#include <cstdio>
#include <queue>
#include <sstream>
#include <string>
#include <algorithm>
#include <map>
#define rep(i, a, b) for (int i = a; i <= b; i++)
#define reps(i, a, b) for (int i = a; i >= b; i--)
#define mk make_pair
using namespace std;
const int N = 1e5 + 7;
const int M = 1e3+ 7;
const int inf = 0x3f3f3f3f;
const int mod = 99824353;
typedef long long ll;
char ch[M][M];
bool flag=0;
int cnt=0;
bool vis[M][M];
int n,m;
bool is[M][M];
void dfs(int x,int y)
{
    if(x<0||x>n+1||y<0||y>m+1||vis[x][y]||ch[x][y]=='1')return;
    vis[x][y]=1;
    if(ch[x][y]=='0')cnt++;
    dfs(x+1,y);dfs(x,y+1);dfs(x-1,y);dfs(x,y-1);
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n){
        scanf("%s",ch[i]+1);
    }
    dfs(0,0);
    printf("%d\n",cnt);
    return 0;
}

你可能感兴趣的:(题解,牛客)