牛客练习赛53补题(D+E)

D.链接:https://ac.nowcoder.com/acm/contest/1114/D
来源:牛客网
 

德育分博弈政治课

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 524288K,其他语言1048576K
64bit IO Format: %lld

题目描述

德育分学长最近玩起了骰子。他玩的骰子不同,他的骰子有六面,每面上写着一个 1 到 9 之间的数字,且六个面上的数字互不相同。现在他手上有 n 个这样的骰子。政治课学长为了在小学妹面前树立威信,决定难为一下德育分。他向德育分提出了 Q 个问题,每个问题是一个字符串,且只含有‘1’~‘9’之间的字符,若德育分可以用他手上的骰子组成这个字符串,则这一回合德育分获胜,否则政治课获胜。若字符串长度为 L,则德育分从他的骰子中选出 L 个,选定每个骰子朝上的面,以一定顺序排列后恰好是这个字符串,则定义为可以组成这个字符串。 

输入描述:

第一行输入 n,Q。
接下来 n 行,每行输入一个长度为 6 的字符串,每个字符都在‘1’~‘9’。
接下来 Q 行,每行一个字符串,每个字符都在‘1’~‘9’。且 Q 个字
符串的总长度不超过 2000000。
1<=n<=500000,1<=Q<=100。

输出描述:

对于每一回合,若德育分获胜,输出“dyf”。
若政治课获胜,输出“zzk”。

示例1

输入

复制

3 3
137628
987654
123456
288
2288
333

输出

复制

dyf
zzk
zzk

题目大意就是给你n个串,每个串可以有6种选择的数字,每个串只能选择一种数字,有Q个询问,每次给你一个询问串s,问你能否用之前给你的那n个串构造出s。

每个骰子限选一个数字,但却有多种不同的选择,看上去是一个网络流类型的题,而且仔细观察会发现,骰子的总个数不会超过C_{9}^{6}种,数字很小,且给你的串s你只需要统计1到9这九个数字的出现个数就好了,所以可以如下构图:

1.源点s链接所有不同种类的骰子,流量为骰子的个数

2.汇点t链接9种数字,流量为询问串s中数字i出现的次数

3.骰子与骰子中出现的数字连边

最后判断最大流是否等于所有出现的数字个数,也就是询问串的长度就好了。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=1e3+10;
const int M=1e5+10;
int n,q;
string sz;
char Q[2000010];
map<string,int>jl;
struct Maxflow{
    int h[N],cur[N],ne[M],to[M],tot,deep[N],s,t,mx;
    int flow[M],ans;
    inline void init(int a,int b,int c){
        s=a;t=b;mx=c;
        for(int i=0;i<M;i++)ne[i]=flow[i]=to[i]=0;
        for(int i=0;i<N;i++)h[i]=cur[i]=0;
        tot=1;ans=0;
    }
    inline void addedge(int x,int y,int z){
        to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=z;
        swap(x,y);
        to[++tot]=y;ne[tot]=h[x],h[x]=tot,flow[tot]=0;
    }
    inline bool bfs(){
        for(int i=0;i<=mx;i++)deep[i]=-1;
        queue<int>q;
        q.push(s);deep[s]=0;
        for(int i=0;i<=mx;i++)cur[i]=h[i];
        while(!q.empty())
        {
            int now=q.front();q.pop();
            for(int i=h[now];i;i=ne[i]){
                int v=to[i];
                if(deep[v]==-1&&flow[i]>0)deep[v]=deep[now]+1,q.push(v);
            }
        }
        return deep[t]!=-1;
    }
    inline int dfs(int u,int op){
        if(u==t||op==0)return op;
        int f=0,us=0;
        for(int i=cur[u];i;i=ne[i]){
            cur[u]=i;
            int v=to[i];
            if(deep[v]==deep[u]+1&&flow[i]>0){
                us=dfs(v,min(op,flow[i]));
                if(!us)continue;
                f+=us;op-=us;
                flow[i]-=us;flow[i^1]+=us;
                if(!op)break;
            }
        }
        if(!f)deep[u]=-1;
        return f;
    }
    inline int maxflow(){
        while(bfs()){
            ans+=dfs(s,inf);
        }
        return ans;
    }
}F;
int gs[10];
void built(){
    int s,t;
    s=1000,t=1001;F.init(s,t,t);int id=9;
    for(auto it:jl){
        int tt=it.second;id++;
        string temp=it.first;
        for(int i=0;i<6;i++){
            F.addedge(id,temp[i]-'0',tt);
        }
        F.addedge(s,id,tt);
    }
    for(int i=1;i<=9;i++)F.addedge(i,t,gs[i]);
}
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        cin>>sz;sort(sz.begin(),sz.end());
        jl[sz]++;
    }
    while(q--){
        scanf("%s",Q+1);int len=strlen(Q+1);
        memset(gs,0,sizeof(gs));
        for(int i=1;i<=len;i++)gs[Q[i]-'0']++;
        built();
        int ans=F.maxflow();
        if(ans==len)puts("dyf");
        else puts("zzk");
    }
}

E.链接:https://ac.nowcoder.com/acm/contest/1114/E
来源:牛客网
 

题目描述

老瞎眼有一个长度为 n 的数组 a,为了为难小鲜肉,他准备了 Q 次询问,每次给出 一个区间[L,R],他让小鲜肉寻 找一对 l,r 使L<=l<=r<=R 且 a[l]^a[l+1]^a[l+2]...^a[r]=0,老瞎眼只让他回答r-l+1 最小是多少,若没有符合条件的 l,r 输出”-1”。 

输入描述:

第一行输入 n,Q。
第二行输入 n 个数,表示 a 数组。
接下来 Q 行,每行输入 L,R。
1<=n,Q<=500000,0<=a[i]<=1000000,1<=L<=R<=n

输出描述:

若有解,输出 r-l+1 最小是多少。
否则输出“-1”。

示例1

输入

复制

4 2
2 1 3 3
1 2
1 3

输出

复制

-1
3

说明

第一次询问无解。
第二次询问:
l=1,r=3

先将所有询问离线,用线段树维护区间最小值,从左到右遍历一遍,并保存当前出现过的所有前缀异或和最靠右出现的位置,如果点i有询问,直接query就好,并且将这个点的前缀异或和的最小距离插入线段树。

#include<bits/stdc++.h>
using namespace std;
 
const int maxn=5e5+10;
struct node{
    int l,r;
    int Min;
}t[maxn<<2];
int a[maxn],n,m,q,ans[maxn],cnt[int(2e6)];
struct que{
    int id,l,r;
}Q[maxn];
int cmp(const que&a,const que&b){
    return a.r<b.r;
}
void build(int u,int l,int r){
    t[u].l=l,t[u].r=r;
    if(l==r){
        t[u].Min=1e9;
        return;
    }
    int mid=(l+r)>>1;
    build(u<<1,l,mid);
    build(u<<1|1,mid+1,r);
    t[u].Min=min(t[u<<1].Min,t[u<<1|1].Min);
}
void  update(int u,int pos,int v){
    int l=t[u].l,r=t[u].r;
    if(l==r){
        t[u].Min=v;
        return;
    }
    int mid=(l+r)>>1;
    if(pos<=mid)update(u<<1,pos,v);
    else update(u<<1|1,pos,v);
    t[u].Min=min(t[u<<1].Min,t[u<<1|1].Min);
}
int query(int u,int L,int R){
    int l=t[u].l,r=t[u].r;
    if(L==l&&R==r){
        return t[u].Min;
    }
    int mid=(l+r)>>1;
    if(R<=mid)return query(u<<1,L,R);
    else if(L>mid)return query(u<<1|1,L,R);
    else return min(query(u<<1,L,mid),query(u<<1|1,mid+1,R));
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cin>>n>>m;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        a[i]^=a[i-1];
    }
    for(int i=1;i<=m;++i){
        cin>>Q[i].l>>Q[i].r;
        Q[i].id=i;
    }
    build(1,1,n);
    //cerr<<"hah"<<endl;
    sort(Q+1,Q+1+m,cmp);
    int id=1;
    cnt[0]=1;
    for(int i=1;i<=n;++i){
        if(cnt[a[i]]){
            update(1,cnt[a[i]],i-cnt[a[i]]+1);
        }
        cnt[a[i]]=i+1;
        while(id<=m&&Q[id].r==i){
            ans[Q[id].id]=query(1,Q[id].l,Q[id].r);
            ++id;
        }
    }
    for(int i=1;i<=m;++i)cout<<(ans[i]==int(1e9)?-1:ans[i])<<'\n';
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值