牛客题集:练习赛69、70

练习赛70

A

尺取即可

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
map<char ,int > mapp;
string ss="puleyaknoi";
char s[maxn];
bool check(){
    for (int i = 0; i <= 9; ++i)
    {
        if (mapp[ss[i]]==0) return false; 
    }
    return true;
}
int t,n,l,r,ans;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    t=read();
    while (t--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        l=r=1;
        mapp.clear();
        mapp[s[1]]=1;
        ans=INF;
        while (r<=n)
        {
            if (check())
            {
                ans=min(ans,r-l+1);
                mapp[s[l]]--;
                l++;
            }
            else
            {
                r++;
                mapp[s[r]]++;
            }
        }
        cout << (ans==INF?-1:ans) <<endl;
    }
    return 0;
}
View Code

 

B

因为题目的要求,字符串每个字母要按顺序出现,那我们只需找到一个字母,再从这个字母位置往后查找下一个字母,每次查找都用二分即可。

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
string ss="puleyaknoi";
char s[maxn];
int a[maxn][27],ans,n,t,l,r,mid,now,mao;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    t=read();
    while (t--)
    {
        scanf("%s",s+1);
        n=strlen(s+1);
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= 26; ++j)
            {
                a[i][j]=a[i-1][j];
            }    
            a[i][s[i]-'a'+1]++;
        }
        for (int j = 1; j <= 26; ++j) a[n+1][j]=a[n][j]+1;
        ans=INF;
        for (int i = 1; i <= n; ++i)
        {
            now = 0;
            if (s[i]=='p')
            {
                l=i;
                for (int j = 1; j <= 9; ++j)
                {
                    r=n;
                    mao=l;
                    while (l<=r)
                    {
                        mid=(l+r)/2;
                        if (a[mid][ss[j]-'a'+1]>=a[mao][ss[j]-'a'+1]+1) r=mid-1;
                            else l=mid+1;
                    }
                    if (l==n+1) 
                    {
                        now=0;
                        break;
                    }
                    else now=max(now,l-i+1);
                }
                if (now!=0) ans= min(ans,now);
            }
        }
        cout << (ans==INF?-1:ans) <<endl;
    }
    return 0;
}
View Code

 

D

用个map记录每次增加的边,同时记录下每个点的出现次数,如果要删去一条边,map可以直接查询是否存在这条边,存在则判断点的出现次数,如果两个点都存在树中 ,说明删掉这条边还存在其他边把他们连起来,树的个数不变;如果两个点都只出现 1 次,说明两个点都只靠这条边连起来形成一颗树,删掉则树的个数 -1。如果要增添一条边,两条边都没出现过的话,树的个数 +1;都存在树中的话,说明两颗树会被合并成一颗树,树的个数 -1.

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<int, int> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
int du[maxn],t,op,u,v,id,x,y,ans;
map<pii,int> mapp;
map<int,int> vis;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    t=read();
    while (t--)
    {
        op=read();
        if (op==1) 
        {
            u=read(),v=read();
            if (!mapp[{u,v}])
            {
                mapp[{u,v}]=mapp[{v,u}]=1;
                if (!vis[u]) vis[u]=++id;
                if (!vis[v]) vis[v]=++id;
                x=vis[u],y=vis[v];
                if (du[x]==0 && du[y]==0) ans++;
                    else if (du[x] && du[y]) ans--;
                du[x]++,du[y]++;
            }
        }else if (op==2)
        {
            u=read(),v=read();
            if (mapp[{u,v}])
            {
                mapp[{u,v}]=mapp[{v,u}]=0;
                x=vis[u],y=vis[v];
                du[x]--,du[y]--;
                if (du[x]==0 && du[y]==0) ans--;
                    else if (du[x] && du[y]) ans++;
            }
        }else
        {
            cout << ans <<endl;
        }
    }
    return 0;
}
View Code

 

练习赛69

B

排个序,把最大的几个都挑出来,总能把这几个数分组

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
int n,a[maxn],x,y;
ll sum[maxn],ans;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    n=read();
    for (int i = 1; i <= n; ++i)
    {
        a[i]=read();
    }
    sort(a+1,a+1+n);
    reverse(a+1,a+1+n);
    for (int i = 1; i <= n; ++i)
    {
        sum[i]=sum[i-1]+a[i];
    }
    x=read(),y=read();
    for (int i = 1; i <= x; ++i)
    {
        for (int j = 1; j <= y; ++j)
        {
            ans+=sum[i*j];
        }
    }
    cout << ans <<endl;
    return 0;
}
View Code

 

C

对答案有贡献的边肯定是最大生成树上的边,因为这棵树是所有选出来的树当中权值总和最大的,那么可以将这些边先拉出来,每条边至少会被贡献一次。

对于一条最大的边,我们要让它产生贡献,那么只能是这条边的两个点产生出来,之后这条边再也不会有所贡献了,同理其他的边,因此可以看出每条边只对答案贡献了一次。

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct node
{
    int u,v,w;
    bool operator<(node& x) const 
    {
        return w>x.w;
    } 
};
vector<node> G;
struct DSU{
    int a[maxn],sz[maxn];
    void init(int n){
        iota(a,a+n+1,0);
        fill(sz,sz+n+1,1);
    }
    int fa(int x){
        return a[x]==x?x:a[x]=fa(a[x]);
    }
    bool query(int x,int y){ //查找
        return fa(x)==fa(y);
    }
    void join(int x,int y){ //合并
        x=fa(x),y=fa(y);
        if(x==y)return;
        if(sz[x]>sz[y])swap(x,y);
        a[x]=y; sz[y]+=sz[x];
    }
    int operator[](int x){return fa(x);}
}d;
int n,m,u,v,w;
ll ans;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    n=read(),m=read();
    d.init(n);
    for (int i = 1; i <= m; ++i)
    {
        u=read(),v=read(),w=read();
        G.pb({u,v,w});
    }
    sort(G.begin(),G.end());
    for (auto x:G)
    {
        if (d.query(x.u,x.v)) continue;
        ans+=x.w;
        d.join(x.u,x.v);
    }
    cout << ans <<endl;
    return 0;
}
View Code

 

D

一个选手的分数 ai 加 d 会导致区间 (ai,ai+d)中的数必须都要+d

那么一个选手就会牵连致其他选手,构成一个团体

考虑分组背包,当前选手不加d,那么就要看前一位选手会不会牵连到他,当前选手加d,那么前一位选手加不加都无所谓。

 

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 5005;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
struct CC{
    static const int N=5005;
    ll fac[N],inv[N];
    CC(){
        fac[0]=1;
        for (int i = 1; i < N; ++i) fac[i]=fac[i-1]*i%mod;
        inv[N-1]=qpow(fac[N-1],mod-2);
        for (int i = N-1; i>= 1; --i) inv[i-1]=inv[i]*i%mod;
    }
    ll operator()(ll a,ll b){ //a>=b
        if(a<b || b<0)return 0;
        return fac[a]*inv[a-b]%mod*inv[b]%mod;
    }
    ll A(ll a,ll b){ //a>=b
        if(a<b || b<0)return 0;
        return fac[a]*inv[a-b]%mod;
    }
}C;
int n;
int d,f[maxn][maxn][2],a[maxn];
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    n=read(),d=read();
    for (int i = 1; i <= n; ++i)
    {
        a[i]=read();
    }
    sort(a+1,a+1+n);
    f[1][0][0]=f[1][1][1]=1;

    for (int i = 2; i <= n; ++i)
    {
        for (int j = 0; j <= n; ++j)
        {
            f[i][j][0]=(f[i][j][0]+f[i-1][j][0])%mod;
            if(a[i-1]+d<=a[i])
                f[i][j][0]=(f[i][j][0]+f[i-1][j][1])%mod;
            if (j+1 <= n)
            {
                f[i][j+1][1]=(f[i][j+1][1]+f[i-1][j][0])%mod;
                f[i][j+1][1]=(f[i][j+1][1]+f[i-1][j][1])%mod;
            }
        }
    }
    for (int i = 1; i <= n; ++i)
    {
        ll ans = f[n][i][0]+f[n][i][1];
        ans %= mod;
        cout << ans*qpow(C(n,i),mod-2)%mod <<endl;
    }
    return 0;
}
View Code

 

E

这题再次学到了……

因为要选择一个区间,这个区间的涉及下标和元素要全部一样,所以他们异或起来的值都是一样的,但是为防止下标和元素不同,异或起来的值相同的情况,我们就给予它们一个哈希值,这样就可以完全避免冲突。

#include <bits/stdc++.h>
#define debug freopen("r.txt","r",stdin)
#define mp make_pair
#define ri register int
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double lf;
typedef pair<ll, ll> pii;
const int maxn = 1e6+10;
const int N = 1500+10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9+7;
const int hash_num = 131;
const double eps=1e-6;
const double PI=acos(-1.0);
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;}
// mt19937_64 rnd(time(0)); unsigned long long
// mt19937 rnd(time(0)); unsigned int
mt19937_64 rnd(time(0));
ll qpow(ll p,ll q){return (q&1?p:1)*(q?qpow(p*p%mod,q/2):1)%mod;}
int n;
ll a[maxn],pre[maxn],ans,k[maxn];
unordered_map<ll,int>mapp;
int main()
{
    #ifndef ONLINE_JUDGE
        debug;
    #endif
    n=read();
    for (int i = 1; i <= n; ++i)
    {
        a[i]=read();
        k[i]=rnd();
    }
    for (int i = 1; i <= n; ++i)
    {
        pre[i] = pre[i-1] ^ k[i] ^ k[a[i]];
    }
    mapp[0]=1;
    for (int i = 1; i <= n; ++i)
    {
        ans+=mapp[pre[i]];
        mapp[pre[i]]++;
    }
    cout << ans <<endl;
    return 0;
}
View Code

 

posted @ 2021-02-20 00:11  Y-KnightQin  阅读(37)  评论(0编辑  收藏  举报