牛客算法周周练8 (A(dp),B(dfs),C(线段树),D(hash),E(思维))

题目链接

说实话,这些题或多或少的做过,或者补过,稍微想想就想到了做法。

A-小A买彩票

做法:dp,设dp[i][j]为前i个数,得到的金额为j,

dp方程:

rep(j,1,4){
            for(int k=10;k<=200;++k)
            dp[i][k+j-3]+=dp[i-1][k];
        }

由于可能会减到负数,所以对所有状态移动到一个比较大的数即可。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int maxn=1e2+10,N=1e2;
ll dp[N][N*N],n;
int main()
{
    n=read();
    dp[0][N]=1;
    rep(i,1,n){
        rep(j,1,4){
            for(int k=10;k<=200;++k)
            dp[i][k+j-3]+=dp[i-1][k];
        }
    }
    ll fz=0;
    for(int i=N;i<=200;++i) fz=fz+dp[n][i];
    ll fm=1ll<<(n*2);
    //printf("fz:%lld fm:%lld\n",fz,fm);
 
    ll gc=gcd(fz,fm);
    fz/=gc,fm/=gc;
    printf("%lld/%lld\n",fz,fm);
}

B-「金」点石成金

做法:n只有15,暴力dfs即可

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define maxn 1005
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
 
inline ll read()
{
    ll x=0,w=1; char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
    while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
    return w==1?x:-x;
}
const int N=20;
ll a[N],b[N],c[N],d[N],ans;
int n;
void dfs(int id,ll mofa,ll money)
{
    if(id>n){
        ans=max(ans,mofa*money);
        return ;
    }
    dfs(id+1,max(0ll,mofa-b[id]),money+a[id]);
    dfs(id+1,mofa+c[id],max(0ll,money-d[id]));
}
int main()
{
    n=read();
    rep(i,1,n)
    {
        a[i]=read();
        b[i]=read();
        c[i]=read();
        d[i]=read();
    }
    ans=-1e18;
    dfs(1,0,0);
    printf("%lld\n",ans);
}

C-小阳的贝壳

做法:线段树维护差分数组,之前写过博客:博客

#include<bits/stdc++.h>
using namespace std;
#define ls id<<1
#define rs id<<1|1
const int N=1e5+10;
int gcd[N*4],mx[N*4],mi[N*4],T[N*4],n,m,a[N];
void up(int id,int l,int r,int pos,int val)
{
    if(l==r)
    {
        mx[id]+=val;
        mi[id]=gcd[id]=mx[id];
        gcd[id]=abs(gcd[id]);
        return ;
    }
    int mid=l+r>>1;
    if(pos<=mid)up(ls,l,mid,pos,val);
    else up(rs,mid+1,r,pos,val);
    mx[id]=max(mx[ls],mx[rs]);
    mi[id]=min(mi[ls],mi[rs]);
    gcd[id]=__gcd(gcd[ls],gcd[rs]);
}
void up2(int id,int l,int r,int ql,int qr,int v)
{
    if(ql<=l&&r<=qr){
        T[id]+=v;
        return;
    }
    int mid=l+r>>1;
    if(ql<=mid) up2(ls,l,mid,ql,qr,v);
    if(qr>mid) up2(rs,mid+1,r,ql,qr,v);
}
int qu2(int id,int l,int r,int pos)
{
    if(l==r) return T[id];
    int res=T[id];
    int mid=l+r>>1;
    if(pos<=mid) res+=qu2(ls,l,mid,pos);
    else res+=qu2(rs,mid+1,r,pos);
    return res;
}
int qu(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr){
        return max(abs(mx[id]),abs(mi[id]));
    }
    int mid=l+r>>1;
    int res=0;
    if(ql<=mid) res=max(res,qu(ls,l,mid,ql,qr));
    if(qr>mid) res=max(res,qu(rs,mid+1,r,ql,qr));
    return res;
}
int qugcd(int id,int l,int r,int ql,int qr)
{
    if(ql<=l&&r<=qr) return gcd[id];
    int mid=l+r>>1;
    if(qr<=mid) return qugcd(ls,l,mid,ql,qr);
    else if(ql>mid) return qugcd(rs,mid+1,r,ql,qr);
    else{
        int t1=qugcd(ls,l,mid,ql,qr);
        int t2=qugcd(rs,mid+1,r,ql,qr);
        return __gcd(t1,t2);
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        up(1,1,n,i,a[i]-a[i-1]);
        up2(1,1,n,i,i,a[i]);
    }
    int ans;
    while(m--){
        int ty,l,r;
        scanf("%d%d%d",&ty,&l,&r);
        if(ty==1){
            int x;
            scanf("%d",&x);
            up(1,1,n,l,x);
            if(r+1<=n) up(1,1,n,r+1,-x);
            up2(1,1,n,l,r,x);
        }
        else if(ty==2){
            if(l==r) printf("0\n");
            else{
                ans=qu(1,1,n,l+1,r);//因为是差分数组,所以l要加1
                printf("%d\n",ans);
            }
        }
        else{
            int v=qu2(1,1,n,l);
            if(l==r) printf("%d\n",v);
            else{
                int gc=qugcd(1,1,n,l+1,r);
                printf("%d\n",__gcd(gc,v));//左端点的值gcd上差分数组内的gcd
            }
        }
    }
}

D-Forsaken喜欢字符串

做法:由于k很小,hash即可  map预处理hash。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+10;
ll base[3]={43,47};
ll h[3][N][10];
ll mod[3]={1000000007,998244353};
ll f[3][N];
int n,k;
const int M=5e4+10;
char s[M][10];
map<pair<int,int>,int>mp;
void init()
{
    f[0][0]=1;
    f[1][0]=1;
    for(int i=1;i<N;++i)
    {
        for(int j=0;j<2;++j) f[j][i]=f[j][i-1]*base[j]%mod[j];
    }
}
pair<int,int> getv(int id,int l,int r)
{
    pair<int,int>p;
    int d1=(h[0][id][r]-h[0][id][l-1]*f[0][r-l+1]%mod[0]+mod[0])%mod[0];
    int d2=(h[1][id][r]-h[1][id][l-1]*f[1][r-l+1]%mod[1]+mod[1])%mod[1];
    p=make_pair(d1,d2);
    return p;
}
int getid(char c)
{
    return c-'0';
}
int main()
{
    init();
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s[i]+1);
        for(int j=1;j<=k;++j)
        {
            for(int k=0;k<2;++k)
            {
                h[k][i][j]=h[k][i][j-1]*base[k]%mod[k]+getid(s[i][j]);
            }
        }
        for(int r=1;r<=k;++r)
        {
            for(int l=1;l<=r;++l)
            {
                pair<int,int>p;
                p=getv(i,l,r);
                mp[p]++;
            }
        }
    }

    int q;
    scanf("%d",&q);

    while(q--)
    {
        int id,len;
        ll ans=0;
        scanf("%d%d",&id,&len);
        for(int r=1;r<=k;++r)
        {
            for(int l=1;l<=r;++l)
            {
                pair<int,int>p;
                p=getv(id,l,r);
                mp[p]--;
            }
        }
        for(int i=1;i+len-1<=k;++i)
        {
            pair<int,int>p;
            p=getv(id,i,i+len-1);
            //printf("l:%d r:%d mp:%d\n",i,i+len-1,mp[p]);
            ans+=1ll*mp[p]*len;
        }
        for(int r=1;r<=k;++r)
        {
            for(int l=1;l<=r;++l)
            {
                pair<int,int>p;
                p=getv(id,l,r);
                mp[p]++;
            }
        }
    printf("%lld\n",ans);
    }

}
/*
3 4
abab
abab
abab
100
3 1
*/

E-Board

做法:找出每行每列的最小值,然后每行每列减去这个最小值,-1的位置就加上这个最小值即可。枚举完毕-1位置加的数就是答案。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define inf 1e9
#define pb push_back
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;

ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
inline ll read()
{
	ll x=0,w=1; char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') w=-1; c=getchar();}
	while(c<='9'&&c>='0') {x=(x<<1)+(x<<3)+c-'0'; c=getchar();}
	return w==1?x:-x;
}
const int N=1e3+10;
int a[N][N],n,ans[N][N];
int main()
{
    n=read();
    rep(i,1,n) rep(j,1,n) a[i][j]=read();
    rep(i,1,n)
    {
        int mi=1e9;
        rep(j,1,n)
        {
            if(a[i][j]==-1) continue;
            mi=min(mi,a[i][j]);
        }
        if(mi==1e9) continue;
        rep(j,1,n){
            if(a[i][j]==-1) ans[i][j]+=mi;
            else a[i][j]-=mi;
        }
    }

    rep(j,1,n)
    {
        int mi=1e9;
        rep(i,1,n)
        {
            if(a[i][j]==-1) continue;
            mi=min(mi,a[i][j]);
        }
        if(mi==1e9) continue;
        rep(i,1,n)
        {
            if(a[i][j]==-1) ans[i][j]+=mi;
            else a[i][j]-=mi;
        }
    }
    rep(i,1,n)
    {
        rep(j,1,n)
        {
            if(a[i][j]==-1){
                printf("%d\n",ans[i][j]);
                return 0;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_41286356/article/details/106364263