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。
每个骰子限选一个数字,但却有多种不同的选择,看上去是一个网络流类型的题,而且仔细观察会发现,骰子的总个数不会超过种,数字很小,且给你的串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;
}