In mathematics you don't understand things, you just get used to them.

标签 brute force 下的文章

Description

Link

给出一个二维平面以及一些点,保证点不在同行 / 同列。每次询问求出一个子矩阵里面的顺序对。

Solution

卡常,卡你吗。

膜拜 dX。

基本是把 dX 的题解贺了过来所以没啥参考的价值。

不过有很多细节的处理不一样,大概能算个 $\frac{1}{50}$ 成新?

对序列分块,把贡献分成 整块 - 散块 / 整块 - 整块/ 散块 - 整块 / 散块 - 散块 以及 散块内部 / 整块内部 共六种贡献。

记 $\textit{ans}_{0}(l,r,x,y)$ 为询问 $l,r,x,y$ 的答案。

同时预处理出 $\textit{lb}(i,j),\textit{ub}(i,j)$ 分别表示在块 $i$ 中数 $j$ 的 std::lower_bound / std::upper_bound 值,下文如果写成单元函数的形式那么就是省去了第一维。

以及预先做一个块内排序,记为 $\textit{ord}(i,j)$,表示块 $i$ 中排序后的第 $j$ 个元素。

注意本文在每个 subtask 定义的东西在其他 subtask 依然适用

  • 散块 - 散块;

两边的都是 $\sqrt{n}$ 级别,拉出来分别排序后归并计算顺序对即可。

  • 散块内部

考虑如何对 $\textit{ans}_{0}(l,r,x,y)$ 进行容斥。

主要矛盾集中在:会出现 $(a\in[1,x),b\in[x,y])$ 这样的贡献。令 $\textit{cnt}_{0}(i,j)$ 表示 $[\textit{lp},i]$ 中 $\textit{rank}_{1}$ 小于 $j$ 的数的数量,其中 $\textit{lp}$ 是当前块的左端点,下同,如果出现 $\textit{rp}$ 同理,$\textit{rank}_{1}$ 的定义见下文。

则容斥可以写为 $\textit{ans}_{0}(l,r,x,y)=\textit{ans}_{0}(l,r,1,y)-\textit{ans}_{0}(l,r,1,x-1)-\sum_{i=l}^{r}[a_{i}\in[x,y]]\cdot\textit{cnt}_{0}(i,\textit{lb}(x)-1)$。

又有 $\textit{ans}_{0}(l,r,1,x)=\sum_{i=l}^{r}[a_{i}\leqslant x]\cdot\textit{cnt}_{0}(i,\textit{rank}_{1}(i))$,我们就可以做到单次 $\mathcal{O}(\sqrt{n})$,注意的 $l,r$ 触及散块边界者不同时,对 $\textit{cnt}_{0}$ 的容斥也有区别。

  • 整块 - 整块

令 $\textit{cnt}_{1}(i,j)$ 为块 $[1,i]$ 中 $\leqslant j$ 的元素个数,$\textit{ans}_{1}(L,R,x,y)$ 为块 $[L,R]$ 的答案,以及 $\textit{rank}_{0}(i,j)$ 是块 $i$ 中排名 $j$ 的元素在原数组中的下标。

我们掏出传统容斥:$\textit{ans}_{1}(L,R,x,y)=\textit{ans}_{1}(L,R,1,y)-\textit{ans}_{1}(L,R,1,x-1)-\sum_{i=L}^{R}P_{i}Q_{i}$,$P_{i}$ 是块 $[L,i)$ 中 $<x$ 的元素个数,$Q_{i}$ 是块 $i$ 种 $\in[x,y]$ 的元素个数。

考虑算 $\textit{ans}_{1}(L,R,1,x)$。

定义 $\textit{rank}_{1}(i,j)$ 为块 $i$ 中第 $j$ 个元素的排名(从小到大,下同),$\textit{rank}_{2}(i,j)$ 为块 $i$ 中满足 $<j$ 的最大元素的排名,$\textit{pre}_{b}(i,j)$ 为块 $[i,j]$ 中所有 $<\textit{rank}_{1}(i,j)$ 的元素数量。

易知 $\textit{pre}_{b}(i,j)=\textit{cnt}_{1}(i,\textit{rank}_{1}(i,j)-1)$,再定义 $\overset{\sqrt{n},\sqrt{n},\sqrt{n}}{\textit{cp}_{0}(i,L,r)}$ 为块 $[1,L]$ 与块 $i$ 前 $r$ 小的元素组成的顺序对数量,同样易知 $\textit{cp}_{0}(i,L,r)=\sum_{k\in T}[\textit{rank}_{1}(i,k)\leqslant r]\cdot\textit{pre}_{b}(L,\textit{rank}_{1}(i,k))$,其中 $T$ 是块 $i$ 的元素集。但这样搞状态数 $\mathcal{O}(n\sqrt{n})$ 转移还要 $\mathcal{\sqrt{n}}$ 而且不好前缀和。

不过可以发现使用 $\textit{ord}$ 数组 $\textit{cp}_{0}$ 就可以递推了:$\textit{cp}_{0}(i,L,r)=\sum_{k=lp}^{r+lp-1}\textit{pre}_{b}(L,k)=\textit{cp}_{0}(i,L,r-1)+\textit{pre}_{b}(L,r+lp-1)$。

然后 $\textit{ans}_{1}(L,R,1,x)=\sum_{i=L+1}^{R}\textit{cp}_{0}(i,i-1,\textit{rank}_{2}(i,x))-\textit{cp}_{0}(i,L-1,\textit{rank}_{2}(i,x))$。

预处理 $\textit{cp}_{0}$ 是 $\mathcal{O}(n\sqrt{n})$,单次回答 $\mathcal{O}(\sqrt{n})$。

  • 散块 - 整块

枚举散块里面的元素,利用 $\textit{cnt}_{1}(i,j)$ 计算答案。

具体是令散块元素集为 $T$,整块编号为 $L,R$, $\sum_{i\in T}\textit{cnt}_{1}(R,i)-\textit{cnt}_{1}(L-1,i)$。

  • 整块 - 散块

和上面有什么区别吗?

  • 整块内部

预处理数组 $\overset{\sqrt{n},\sqrt{n},\sqrt{n}}{\textit{cp}_{1}(i,x,y)}$ 表示取 $\textit{ord}(i,x\dots y)$ 组成的序列的顺序对数量。

用 $\textit{rank}_{0}$ 来预处理:$\textit{cp}_{1}(i,x,y)=\textit{cp}_{1}(i,x,y-1)+\textit{cnt}_{0}(\textit{rank}_{0}(i,y),y-1)-\textit{cnt}_{0}(\textit{rank}_{0}(i,y),x-1)$。


综上,这个问题得以一个 $\mathcal{O}(n\sqrt{n})$ 的在线算法解决。

代码也是抄的 dX,像个 shit 一样就折叠了。

//almost copied from dead_X sry
//kouhu has no qiantu
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
#define getchar() (p1==p2 && (p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
inline int Read()
{
    int x=0;char c=getchar();
    while(c<'0' || c>'9') c=getchar();
    while(c>='0' && c<='9') x=x*10+(c&15),c=getchar();
    return x;
}
const int N=101111,A=460,BS=A+10;
ll cp0[BS][BS][BS];
int a[N],rk0[BS][BS],cnt0[BS][N],cp1[BS][BS][BS],lb[BS][N],rk1[N],cnt1[BS][N],L[BS],R[BS];
bool cmp(int x,int y) { return a[x]<a[y]; }
namespace IO{
    const int sz=1<<22;
    char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
    inline char gc(){
        return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;
    }
    template<class T> void gi(T& x){
        x=0; char c=gc();
        for(;c<'0'||c>'9';c=gc());
        for(;c>='0'&&c<='9';c=gc())
            x=(x<<3)+(x<<1)+(c-'0');
    }
    inline void flush(){fwrite(b,1,t-b,stdout),t=b; }
    inline void pc(char x){*t++=x; if(t-b==sz) flush(); }
    template<class T> void pi(T x,char c='\n'){
        if(x<0) x=-x;
        if(x==0) pc('0'); int t=0;
        for(;x;x/=10) p[++t]=x%10+'0';
        for(;t;--t) pc(p[t]); pc(c);
    }
    struct F{~F(){flush();}}f; 
}
using IO::gi;
using IO::pi;
inline int read() { int r; gi(r); return r; }
int main(){
#ifdef ONLINE_JUDGE
    freopen("tears.in","r",stdin);
    freopen("tears.out","w",stdout);
#endif
    int n=read(),m=read(),B=n/A;
    for(int i=0;i<n;++i)a[i]=read();
    for(int i=n;i<(B+1)*A;++i)a[i]=i;
    for(int i=0;i<=B;++i){
        for(int j=i*A,k=0;k<A;++j,++k)rk0[i][k]=j;
        sort(rk0[i],rk0[i]+A,[](int x,int y){return a[x]<a[y];});
        for(int j=0;j<A;++j)rk1[rk0[i][j]]=j,cnt0[j][rk0[i][j]]=1;
        for(int j=i*A+1;j<(i+1)*A;++j)
            for(int k=0;k<A;++k)cnt0[k][j]+=cnt0[k][j-1];
        for(int j=i*A;j<(i+1)*A;++j)
            for(int k=1;k<A;++k)cnt0[k][j]+=cnt0[k-1][j];
        for(int j=i*A;j<(i+1)*A;++j)++cnt1[i][a[j]];
        if(i)for(int j=1;j<=101000;++j)cnt1[i][j]+=cnt1[i-1][j];
        for(int j=1,k=0;j<=101000;++j)(k<A)&&(j>=a[rk0[i][k]])&&(++k),lb[i][j]=k;
    }
    for(int i=0;i<=B;++i)
        for(int j=1;j<=101000;++j)cnt1[i][j]+=cnt1[i][j-1];
    for(int i=1;i<B;++i)for(int j=0;j<i;++j)for(int k=0;k<A;++k)
        cp0[i][j][k+1]=cnt1[j][a[rk0[i][k]]]+cp0[i][j][k];
    for(int i=0;i<B;++i)for(int j=0;j<A;++j)for(int k=j+1;k<A;++k)
        cp1[i][j][k]=cp1[i][j][k-1]+cnt0[k-1][rk0[i][k]]-((j==0)?0:cnt0[j-1][rk0[i][k]]);
    for(;m;--m){
        int l=read()-1,r=read()-1,x=read(),y=read(),bl=l/A,br=r/A;
        if(bl==br){
            int ans=0;
            for(int i=l;i<=r;++i){
                if(x<=a[i]&&a[i]<=y&&rk1[i])ans+=cnt0[rk1[i]-1][i]-((l%A)?cnt0[rk1[i]-1][l-1]:0);
                if(lb[bl][x-1]&&x<=a[i]&&a[i]<=y)ans-=cnt0[lb[bl][x-1]-1][i]-((l%A&&lb[bl][x-1])?cnt0[lb[bl][x-1]-1][l-1]:0);
            }
            pi(ans);
        }
        else{
            ll ans=0;
            for(int i=l;i<(bl+1)*A;++i){
                if(x<=a[i]&&a[i]<=y&&rk1[i])ans+=cnt0[rk1[i]-1][i]-((l%A)?cnt0[rk1[i]-1][l-1]:0);
                if(lb[bl][x-1]&&x<=a[i]&&a[i]<=y)ans-=cnt0[lb[bl][x-1]-1][i]-((l%A&&lb[bl][x-1])?cnt0[lb[bl][x-1]-1][l-1]:0);
                if(x<=a[i]&&a[i]<=y)ans+=cnt1[br-1][y]-cnt1[bl][y]-cnt1[br-1][a[i]]+cnt1[bl][a[i]];
            }
            for(int i=br*A;i<=r;++i){
                if(x<=a[i]&&a[i]<=y&&rk1[i])ans+=cnt0[rk1[i]-1][i];
                if(lb[br][x-1]&&x<=a[i]&&a[i]<=y)ans-=cnt0[lb[br][x-1]-1][i];
                if(x<=a[i]&&a[i]<=y)ans+=cnt1[br-1][a[i]]-cnt1[bl][a[i]]-cnt1[br-1][x-1]+cnt1[bl][x-1];
            }
            int lt=0,rt=0;
            for(int i=0;i<A;++i){
                if(rk0[bl][i]>=l&&x<=a[rk0[bl][i]]&&a[rk0[bl][i]]<=y)L[++lt]=rk0[bl][i];
                if(rk0[br][i]<=r&&x<=a[rk0[br][i]]&&a[rk0[br][i]]<=y)R[++rt]=rk0[br][i];
            }
            for(int i=1,t=1;i<=rt;++i){
                while(t<=lt&&a[L[t]]<a[R[i]])++t;
                ans+=t-1;
            }
            for(int i=bl+1;i<br;++i)if(lb[i][y])ans+=cp1[i][lb[i][x-1]][lb[i][y]-1];
            for(int i=bl+2;i<br;++i)
                ans+=cp0[i][i-1][lb[i][y]]-cp0[i][bl][lb[i][y]]-cp0[i][i-1][lb[i][x-1]]+cp0[i][bl][lb[i][x-1]],
                ans-=ll(cnt1[i][y]-cnt1[i-1][y]-cnt1[i][x-1]+cnt1[i-1][x-1])*(cnt1[i-1][x-1]-cnt1[bl][x-1]);
            pi(ans);
        }
    }
    return 0;
}

我是傻逼。

「CF 1539A」Contest Start

Link.

答案是 $\sum_{i=1}^{n-1}\min\{i,\lfloor\frac{t}{x}\rfloor\}$,等差数列求和优化。

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
#define all(x) (x).begin(),(x).end()
using namespace std;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int main(){
    int T;
    ll n,x,t;
    for(sf(T);T;--T){
        sf(n),sf(x),sf(t);
        ll ans=0,d=t/x;
        --n;
        if(n>=d)ans=(n-d)*d+d*(d+1)/2;
        else ans=n*(n+1)/2;
        pf(ans);
    }
    return 0;
}

「CF 1539B」Love Song

Link.

暴力。

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
#define all(x) (x).begin(),(x).end()
using namespace std;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int cap[100010][26],n,q;
char ch[100010];
int main(){
    sf(n),sf(q);
    scanf("%s",ch+1);
    for(int i=1;i<=n;++i){
        memcpy(cap[i],cap[i-1],sizeof(int)*26);
        cap[i][ch[i]-'a']++;
    }
    for(int l,r;q;--q){
        sf(l),sf(r);
        ll ans=0;
        for(int i=0;i<26;++i)ans+=(i+1)*(cap[r][i]-cap[l-1][i]);
        pf(ans);
    }
    return 0;
}

「CF 1539C」Stable Groups

Link.

贪心。

对原序列差分,把差分值拿出来排序后把前几个填了。正确性显然。

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
#define all(x) (x).begin(),(x).end()
using namespace std;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
int n;
ll a[200010],k,x,df[200010];
int main(){
    sf(n);sf(k);sf(x);for(int i=1;i<=n;++i)sf(a[i]);
    sort(a+1,a+n+1);
    for(int i=2;i<=n;++i)df[i]=a[i]-a[i-1];
    vector<ll> ald;
    for(int i=2;i<=n;++i){
        if(df[i]>x)ald.emplace_back(df[i]);
    }
    sort(all(ald));
    int del=0;
    for(int i=0;i<int(ald.size());++i){
        ll w=ald[i];
        if(w%x==0){
            if(k>=w/x-1)k-=w/x-1,++del;
            else break;
        }
        else{
            if(k>=w/x)k-=w/x,++del;
            else break;
        }
    }
    pf(int(ald.size())-del+1);
    return 0;
}

「CF 1539D」PriceFixed

Link.

以 $b$ 为关键字排序。

首先考虑把第一个元素「激活」,即填满 $b_{1}$ 个商品。

然后后面的元素有两种决策:

  1. 使用前面已经「激活」的商品来「激活」该商品后买完;
  2. 直接买 $a_{i}$ 个,注意分 $a_{i},b_{i}$ 大小讨论。

两种决策会使总买入商品数不一致,对后面有影响(?)。

现在考场上那个傻逼在想 DP。

但是注意到这样搞的代价是没有差别的,$2-1=1$ 抵了。

那么就一定存在一种最优方案使得每种产品买恰好 $a_{i}$ 个,搞两个指针扫一下就行了。

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
#define all(x) (x).begin(),(x).end()
using namespace std;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
struct st{ll a,b;}a[100010];
int n;
int main(){
    sf(n);for(int i=1;i<=n;++i)sf(a[i].a),sf(a[i].b);
    sort(a+1,a+n+1,[](st x,st y){return x.b<y.b || (x.b==y.b && x.a<y.a);});
    ll nw=0,ans=0;
    for(int i=1,j=n;i<=j;){
        if(nw>=a[i].b){
            ans+=a[i].a;
            nw+=a[i].a;
            ++i;
        }
        else{
            if(a[j].a+nw>=a[i].b){
                ll temp=a[i].b-nw;
                ans+=2*temp;
                nw+=temp;
                a[j].a-=temp;
            }
            else{
                ans+=a[j].a*2;
                nw+=a[j].a;
                --j;
            }
        }
    }
    pf(ans);
    return 0;
}

「CF 1539E」Game with Cards

Link.

gap 略大。搞不动先咕着。

「CF 1539F」Strange Array

Link.

假的,懒得写了,具体看 Rainybunny 的评论吧。

$\ \ \ \ $F:发现对于某个 $a_{i}$,已知包含它的某个区间中,$\le a_{i}$ 与 $>a_{i}$ 的数的数量差就能得到它的特征值。不妨令“大于等于”为 $+1$,“小于”为 $-1$,线段树维护区间最大前缀和与最大后缀和,升序扫描 $a$ 值就能更新答案。$+1,-1$ 反过来再做一遍,最后是 $\mathcal O(n\log_{2}n)$ 的。
$\ \ \ \ $赛后瞬间补题的原因大概是细节有点多√

#include<bits/stdc++.h>
#define con(typ) const typ
typedef long long ll;
#define all(x) (x).begin(),(x).end()
using namespace std;
template<typename T>void sf(T &x){x=0;T f=0;char c=getchar();for(;c<'0'||c>'9';c=getchar())if(c=='-')f=1;for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+(c^'0');if(f)x=-x;}
template<typename T>void pf(T x,char l='\n'){static int s[100],t;if(x<0)putchar('-'),x=-x;do s[++t]=x%10,x/=10;while(x);while(t)putchar(s[t--]^'0');putchar(l);}
template<typename T,typename... Tt>void sf(T &x,Tt&... aa){sf(x),sf(aa...);}
int n,a[200010],stp,Segres;
vector<int> ps[200010];
struct node{int p,s,sm;node(int a=0,int b=0,int c=0){p=a;s=b;sm=c;}};
struct Segtree{
    const int n;
    vector<node> ns;
    Segtree(int n,int fl):n(n),ns(n*4+5){give(1,n,1,fl);}
    node mrg(node a,node b){
        node c;
        c.p=max(a.p,a.sm+b.p);
        c.s=max(b.s,b.sm+a.s);
        c.sm=a.sm+b.sm;
        return c;
    }
    void give(int l,int r,int p,int v){
        if(r-l==0){ns[p]=node(max(v,0),max(v,0),v);return;}
        int m=(l+r)/2;
        give(l,m,p*2,v),give(m+1,r,p*2+1,v);
        ns[p]=mrg(ns[p*2],ns[p*2+1]);
    }
    void ins(int l,int r,int p,int x,int v){
        if(r-l==0){ns[p]=node(max(v,0),max(v,0),v);return;}
        int m=(l+r)/2;
        if(m>=x)ins(l,m,p*2,x,v);
        else ins(m+1,r,p*2+1,x,v);
        ns[p]=mrg(ns[p*2],ns[p*2+1]);
    }
    void qpre(int l,int r,int p,int x){
        if(l>=x){stp=max(stp,Segres+ns[p].p);Segres+=ns[p].sm;return;}
        int m=(l+r)/2;
        if(m>=x)qpre(l,m,p*2,x);qpre(m+1,r,p*2+1,x);
    }
    void qsuf(int l,int r,int p,int x){
        if(r<=x){stp=max(stp,Segres+ns[p].s);Segres+=ns[p].sm;return;}
        int m=(l+r)/2;
        if(m<x)qsuf(m+1,r,p*2+1,x);qsuf(l,m,p*2,x);
    }
    void ins(int x,int y){ins(1,n,1,x,y);}
    int qpre(int x){Segres=stp=0;qpre(1,n,1,x);return stp;}
    int qsuf(int x){Segres=stp=0;qsuf(1,n,1,x);return stp;}
};
int main(){
    sf(n);for(int i=1;i<=n;++i)sf(a[i]),ps[a[i]].emplace_back(i);
    int value=1;
    vector<int> ans(n);
    for(int value=1;value>-2;value-=2){
        Segtree t(n,value);
        for(int i=1;i<=n;++i){
            if(value==-1)for(int x:ps[i])t.ins(x,-value);
            for(int x:ps[i]){
                int r0,r1;
                r1=t.qpre(x);
                r0=t.qsuf(x);
                if((r0+r1-1)&1)ans[x-1]=max(ans[x-1],(r0+r1-1)/2);
                else{
                    if(value==1)ans[x-1]=max(ans[x-1],(r0+r1-1)/2);
                    else ans[x-1]=max(ans[x-1],(r0+r1-2)/2);
                }
            }
            if(value==1)for(int x:ps[i])t.ins(x,-value);
        }
    }
    for(int x:ans)pf(x,' ');
    return 0;
}

这 1+2?

「CF1534 A」Colour the Flag

Link.

W / R 拉出来广搜,注意判断全空的情况。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T, n, m;
    std::vector<std::vector<int>> DIR({{1, 0}, {0, 1}, {-1, 0}, {0, -1}});
    for (std::cin >> T; T; --T) {
        std::cin >> n >> m;
        std::vector<std::vector<char>> a(n, std::vector<char>(m));
        std::vector<std::vector<bool>> vis(n, std::vector<bool>(m));
        std::queue<std::pair<int, int>> que;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                std::cin >> a[i][j];
                if (a[i][j] != '.') {
                    que.emplace(i, j);
                    vis[i][j] = true;
                }
            }
        }
        if (que.empty()) {
            a[0][0] = 'R';
            que.emplace(0, 0);
            vis[0][0] = true;
        }
        auto check = [&] (std::pair<int, int> x) {
            return x.first < 0 || x.first >= n || x.second < 0 || x.second >= m;
        };
        bool flag = 0;
        while (!que.empty()) {
            auto x = que.front();
            que.pop();
            for (auto d : DIR) {
                auto y = std::make_pair(x.first + d[0], x.second + d[1]);
                if (check(y)) continue;
                if (a[x.first][x.second] == a[y.first][y.second]) {
                    flag = true;
                    break;
                }
                if (vis[y.first][y.second]) continue;
                vis[y.first][y.second] = true;
                if (a[y.first][y.second] == '.') {
                    if (a[x.first][x.second] == 'R') a[y.first][y.second] = 'W';
                    else a[y.first][y.second] = 'R';
                }
                que.emplace(y);
            }
            if (flag) break;
        }
        if (flag) std::cout << "No\n";
        else {
            std::cout << "Yes\n";
            for (auto x : a) {
                for (auto y : x) std::cout << y;
                std::cout << "\n";
            }
        }
    }
    return 0;
}

「CF1534 B」Histogram Ugliness

Link.

我们只会对比 $i+1$ & $i-1$ 都高 $i$ 进行操作,然后答案显然。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T, n;
    for (std::cin >> T; T; --T) {
        std::cin >> n;
        std::vector<int> a(n);
        for (int &x : a) std::cin >> x;
        a.emplace(a.begin(), 0);
        a.emplace_back(0);
        ll ans = 0;
        for (int i = 1; i <= n + 1; ++i) ans += std::abs(a[i] - a[i - 1]);
        for (int i = 1; i <= n; ++i) {
            if (a[i] > std::max(a[i - 1], a[i + 1])) {
                ans -= a[i] - std::max(a[i - 1], a[i + 1]);
                a[i] = std::max(a[i - 1], a[i + 1]);
            }
        }
        std::cout << ans << "\n";
    }
    return 0;
}

「CF1534 C」Little Alawn's Puzzle

Link.

钦定研究第一行。考虑 $i$ 这个下标,我们对在第二行的 $i$ 连个边,同时对在第二行的 $p_{i}$ 的所在下标连边。

然后数出图里面有多少环,答案就是 $2$ 的环数量次方。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int T, n;
    for (std::cin >> T; T; --T) {
        std::cin >> n;
        std::vector<std::vector<int>> a(2, std::vector<int>(n)), idx(2, std::vector<int>(n));
        int cur = 0;
        for (int &x : a[0]) {
            std::cin >> x;
            --x;
            idx[0][x] = cur++;
        }
        for (int &x : a[1]) {
            std::cin >> x;
            --x;
            idx[1][x] = cur++;
        }
        bool flag = false;
        for (int i = 0; i < n; ++i) {
            if (a[0][i] == a[1][i]) {
                flag = true;
                break;
            }
        }
        if (flag) {
            std::cout << "0\n";
            continue;
        }
        std::vector<int> fa(n * 2);
        std::iota(all(fa), 0);
        auto find = [&] (int x) {
            while (fa[x] != x) {
                x = fa[x] = fa[fa[x]];
            }
            return x;
        };
        auto merge = [&] (int x, int y) {
            x = find(x);
            y = find(y);
            fa[x] = y;
        };
        for (int i = 0; i < n; ++i) {
            merge(i, i + n);
            merge(idx[0][a[0][i]], idx[1][a[0][i]]);
        }
        int num = 0;
        for (int i = 0; i < n * 2; ++i) {
            if (fa[i] == i) ++num;
        }
        constexpr int P = 1e9 + 7;
        auto power = [&] (int x, int y) {
            int res = 1;
            for (; y; y >>= 1, x = ll(x) * x % P)
                if (y & 1) res = ll(res) * x % P;
            return (res + P) % P;
        };
        std::cout << power(2, num) << "\n";
    }
    return 0;
}

「CF1534 D」Lost Tree

Link.

首先肯定要钦定一个根,对其进行一次询问。

然后查询出来的相当于是深度。观察次数限制 $\lceil\frac{n}{2}\rceil$,大概是一半的节点。

考虑如何规划一半的节点去询问。一次询问能确定的边就是查询出来距离为 $1$ 的。

注意到相邻奇数偶数之间总是相差 $1$。

然后把节点进行关于深度的奇偶分层,查询 奇 / 偶 中数量较少的节点即可。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
//    std::ios_base::sync_with_stdio(false);
//    std::cin.tie(nullptr);
//    std::cout.tie(nullptr);
    int n;
    std::cin >> n;
    auto ask = [&] (int x) {
        std::cout << "? " << x + 1 << "\n";
        std::vector<int> res(n);
        for (int &x : res) std::cin >> x;
        return res;
    };
    std::vector<int> d = ask(0);
    std::vector<std::pair<int, int>> ans;
    std::vector<std::vector<int>> cat(2);
    for (int i = 0; i < n; ++i) {
        if (d[i] == 1) ans.emplace_back(std::make_pair(0, i));
    }
    for (int i = 1; i < n; ++i) {
        if (d[i] & 1) cat[1].emplace_back(i);
        else cat[0].emplace_back(i);
    }
    std::vector<int> point;
    if (cat[0].size() > cat[1].size()) point = cat[1];
    else point = cat[0];
    for (int x : point) {
        d = ask(x);
        for (int i = 0; i < n; ++i) {
            if (d[i] == 1) ans.emplace_back(std::make_pair(x, i));
        }
    }
    for (auto &x : ans) {
        if (x.first > x.second) std::swap(x.first, x.second);
    }
    std::sort(all(ans));
    ans.erase(std::unique(all(ans)), ans.end());
    std::cout << "!\n";
    for (auto x : ans) std::cout << x.first + 1 << " " << x.second + 1 << "\n";
    return 0;
}

「CF1534 E」Lost Array

Link.

将询问的次数看作一个状态,我们考虑它每次往哪里跑。

如果我们想知道新的 $\texttt{XOR}$ 和可以选择全部查没选过的也可以部分选择。

那么就可以做了,因为 $k$ 很小,BFS 搜即可。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
//    std::ios_base::sync_with_stdio(false);
//    std::cin.tie(nullptr);
//    std::cout.tie(nullptr);
    constexpr int INF = std::numeric_limits<int>::max() / 2;
    int n, k;
    std::cin >> n >> k;
    auto ask = [&] (std::vector<int> v) {
        std::cout << "?";
        for (int x : v) std::cout << " " << x + 1;
        std::cout << "\n";
        int res;
        std::cin >> res;
        return res;
    };
    auto link = [&] (std::vector<int> a, std::vector<int> b) {
        std::vector<int> v;
        for (int x : a) v.emplace_back(x);
        for (int x : b) v.emplace_back(x);
        return v;
    };
    std::vector<int> pre(n + 1, 0), dis(n + 1, INF);
    std::queue<int> que;
    pre[0] = -1;
    dis[0] = 0;
    que.emplace(0);
    while (!que.empty()) {
        int x = que.front();
        que.pop();
        for (int i = 1; i <= k; ++i) {
            if (i <= n - x && k - i <= x) {
                int y = x + i * 2 - k;
                if (dis[y] == INF) {
                    dis[y] = dis[x] + 1;
                    pre[y] = x;
                    que.emplace(y);
                }
            }
        }
    }
    if (dis[n] == INF) {
        std::cout << "-1\n";
        return 0;
    }
    std::vector<int> t, f(n), p;
    for (int i = n; ~i; i = pre[i]) p.emplace_back(i);
    std::reverse(all(p));
    int ans = 0;
    std::iota(all(f), 0);
    for (size_t i = 0; i < p.size() - 1; ++i) {
        int x = (p[i + 1] - p[i] + k) / 2, y = k - x;
        std::vector<int> mt, mf;
        for (int j = 0; j < x; ++j) {
            mt.emplace_back(f.back());
            f.pop_back();
        }
        for (int j = 0; j < y; ++j) {
            mf.emplace_back(t.back());
            t.pop_back();
        }
        ans ^= ask(link(mt, mf));
        t.insert(t.end(), all(mt));
        f.insert(f.end(), all(mf));
    }
    std::cout << "! " << ans << "\n";
    return 0;
}

「CF1534 F1」Falling Sand (Easy Version)

Link.

考虑将一块沙块向其能影响到的沙块连有向边。

具体来讲,我们设 $\textit{last}(i,j)$ 为第 $i$ 行第 $j$ 列往下望见的第一个沙块,若没有则设为 $-1$。然后连边方式就是(研究 $(i,j)$):

  1. 首先 $(i,j)$ 本身是沙块;
  2. 向 $\textit{last}(i,j)$ 连边(如果存在,下同);
  3. 若 $(i,j+1)$ 存在,则连 $(i,j+1)$,否则连 $\textit{last}(i,j+1)$;
  4. $(i,j-1)$ 同理。

连出来一张图,你可能觉得这张图里面所有出度为 $0$ 的就是答案,实则需要缩个点,然后才成立(样例 #2 就能 hack 非常良心)。

#include <bits/stdc++.h>
using ll = long long;
#define all(x) (x).begin(), (x).end()
int main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int n, m, cnt = 0;
    std::cin >> n >> m;
    std::vector<std::vector<char>> a(n, std::vector<char>(m));
    std::vector<std::vector<int>> last(n, std::vector<int>(m)), id = last;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            std::cin >> a[i][j];
            if (a[i][j] == '#') id[i][j] = cnt++;
        }
    }
    for (int j = 0; j < m; ++j) {
        int pos = -1;
        for (int i = n - 1; ~i; --i) {
            last[i][j] = pos;
            if (a[i][j] == '#') pos = i;
        }
    }
    int col = 0, tot = 0;
    std::vector<std::pair<int, int>> edgeSet;
    std::vector<std::vector<int>> e(cnt);
    std::vector<int> color(cnt), order(cnt), low(cnt);
    std::vector<bool> inStk(cnt);
    std::stack<int> stk;
    auto add = [&] (int x, int y) {
        e[x].emplace_back(y);
        edgeSet.emplace_back(std::make_pair(x, y));
    };
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (a[i][j] == '#') {
                if (j < m - 1) {
                    if (a[i][j + 1] == '#') add(id[i][j], id[i][j + 1]);
                    else if (~last[i][j + 1]) add(id[i][j], id[last[i][j + 1]][j + 1]);
                }
                if (j > 0) {
                    if (a[i][j - 1] == '#') add(id[i][j], id[i][j - 1]);
                    if (~last[i][j - 1]) add(id[i][j], id[last[i][j - 1]][j - 1]);
                }
                if(~last[i][j]) add(id[i][j], id[last[i][j]][j]);
                if (i > 0) {
                    if (a[i - 1][j] == '#') add(id[i][j], id[i - 1][j]);
                }
            }
        }
    }
    std::function<void(int)> compress = [&] (int x) {
        order[x] = low[x] = tot++;
        inStk[x] = true;
        stk.emplace(x);
        for (int y : e[x]) {
            if (!order[y]) {
                compress(y);
                low[x] = std::min(low[x], low[y]);
            }
            else if (inStk[y]) low[x] = std::min(low[x], order[y]);
        }
        if (order[x] == low[x]) {
            int y = 0;
            ++col;
            while (x != y) {
                y = stk.top();
                stk.pop();
                color[y] = col;
                inStk[y] = false;
            }
        }
    };
    for (int i = 0; i < cnt; ++i) {
        if (!order[i]) compress(i);
    }
    std::vector<int> deg(col);
    for (std::pair<int, int> edge : edgeSet) {
        if (color[edge.first] != color[edge.second]) ++deg[color[edge.second]];
    }
    std::cout << std::count(all(deg), 0) << "\n";
    return 0;
}

「CF1534 F2」Falling Sand (Hard Version)

Link.

「CF1534 G」A New Beginning

Link.

「CF1534 H」Lost Nodes

Link.

Description

Link.

给定长度为 $n$ 的序列 $a_1, a_2, \dots, a_n$;共 $m$ 组询问,每次询问给出 $d,p_1,p_2$,求

$$ \sum_{i=0}^{d-1} \sum_{j=0}^{d-1} \sum_{k=0}^{d-1} a_{p_1+d\cdot i+j} a_{p_2 + d\cdot j + k} $$

Solution

$$ \sum_{i=0}^{d-1}\sum_{j=0}^{d-1}\sum_{k=0}^{d-1}a(p+di+j)a(q+dj+k) \\ \begin{aligned} &=\sum_{i=0}^{d-1}\sum_{j=0}^{d-1}a(p+di+j)\sum_{k=0}^{d-1}a(q+dj+k) \\ &=\sum_{j=0}^{d-1}\left(\sum_{i=0}^{d-1}a(p+di+j)\right)\left(\sum_{k=0}^{d-1}a(q+dj+k)\right) \\ &=\sum_{j=0}^{d-1}\left(\sum_{i=0}^{d-1}a(p+di+j)\right)\left(pre(q+dj+d-1)-pre(q+dj-1)\right) \\ \end{aligned} $$

由题意,$q+dj+k\le n$,也就是说 $q+d(d-1)+d(-1)=q+d^{2}\le n$,$q_{\min}=1$,所以 $d$ 是根号规模。

那么就可以直接来了,设 $s(i,j)$ 为前缀 $i$ 的间隔 $j$ 前缀和。比如 $\texttt{1 2 3 4 5 6}$ 的 $s(6,2)=12$,也就是 $\texttt{1}$$\texttt{ 2}$$\texttt{ 3}$$\texttt{ 4}$$\texttt{ 5}$$\texttt{ 6}$,蓝色表示被计入贡献,这个东西显然可以递推。

然后把这个带进式子

$$ \sum_{j=0}^{d-1}\left(\sum_{i=0}^{d-1}a(p+di+j)\right)\left(pre(q+dj+d-1)-pre(q+dj-1)\right) \\ \begin{aligned} &=\sum_{j=0}^{d-1}\left(s(p+j+d(d-1),d)-s(p+j,d)+a(p+j)\right)\left(pre(q+dj+d-1)-pre(q+dj-1)\right) \\ \end{aligned} $$

然后就可以直接算了。

然后你会发现你被卡常了,于是把 $s(i,j)$ 换成 $s(j,i)$,前面是根号大小寻址更快,就可以无压力过掉了。

#include<bits/stdc++.h>
typedef unsigned int ui;
const int border=450;
int n,m,opd,opp,opq;
ui a[200010],s[500][200010],prs[200010],ans;
namespace IO{
    const int sz=1<<22;
    char a[sz+5],b[sz+5],*p1=a,*p2=a,*t=b,p[105];
    inline char gc(){
        return p1==p2?(p2=(p1=a)+fread(a,1,sz,stdin),p1==p2?EOF:*p1++):*p1++;
    }
    template<class T> void gi(T& x){
        x=0; char c=gc();
        for(;c<'0'||c>'9';c=gc());
        for(;c>='0'&&c<='9';c=gc())
            x=(x<<3)+(x<<1)+(c-'0');
    }
    inline void flush(){fwrite(b,1,t-b,stdout),t=b; }
    inline void pc(char x){*t++=x; if(t-b==sz) flush(); }
    template<class T> void pi(T x,char c='\n'){
        if(x<0) x=-x;
        if(x==0) pc('0'); int t=0;
        for(;x;x/=10) p[++t]=x%10+'0';
        for(;t;--t) pc(p[t]); pc(c);
    }
    struct F{~F(){flush();}}f; 
}
using IO::gi;
using IO::pi;
int main()
{
    gi(n);
    for(int i=1;i<=n;++i)    gi(a[i]),prs[i]=prs[i-1]+a[i];
    for(int j=1;j<=border;++j)
    {
        for(int i=1;i<=j;++i)    s[j][i]=a[i];
        for(int i=j+1;i<=n;++i)    s[j][i]=s[j][i-j]+a[i];
    }
    gi(m);
    while(m--)
    {
        gi(opd),gi(opp),gi(opq);
        ans=0;
        for(int i=0;i<opd;++i)    ans+=(s[opd][opp+i+opd*(opd-1)]-s[opd][opp+i]+a[opp+i])*(prs[opq+opd*i+opd-1]-prs[opq+opd*i-1]);
        pi(ans);
    }
    return 0;
}

「CF 1490A」Dense Array

Link.

显然不满足的 adjacent elements 之间一直加 $\min\times2,\min\times4,\cdots,\min\times2^{k}$,满足 $\min\times2^{k}\le\max$ 即可。

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int t,n,a[60],ans;
bool judge(double one,double ano)
{
    return max(one,ano)/min(one,ano)<=2.0;
}
int jump(int one,int ano)
{
    int cone=min(one,ano),cano=max(one,ano),res=0;
    while(cone<=cano)
    {
        if((cone<<1)>=cano)    break;
        else
        {
            cone<<=1;
            res++;
        }
    }
    return res;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        ans=0;
        scanf("%d",&n);
        for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
        for(int i=2;i<=n;++i)    ans+=judge(a[i],a[i-1])?0:jump(a[i],a[i-1]);
        printf("%d\n",ans);
    }
    return 0;
}

「CF 1490B」Balanced Remainders

Link.

把原序列的 $c_{0\sim2}$ 统计出来然后贪心(具体怎么贪看代码,不好描述)模拟。

#include<cstdio>
#include<algorithm>
using namespace std;
int t,n,a[30010],c[3],ans;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            ++c[a[i]%3];
        }
        while((c[0]^c[1])||(c[0]^c[2]))
        {
            ans++;
            if(c[0]==*max_element(c,c+3))
            {
                --c[0];
                ++c[1];
            }
            else if(c[1]==*max_element(c,c+3))
            {
                --c[1];
                ++c[2];
            }
            else
            {
                --c[2];
                ++c[0];
            }
        }
        printf("%d\n",ans);
        for(int i=0;i<3;++i)    c[i]=0;
        ans=0;
    }
    return 0;
}

「CF 1490C」Sum of Cubes

Link.

枚举一个 $a$,然后判断 $n-a^{3}$ 是否为完全立方数即可,这个可以二分,注意二分的范围不要乱搞,容易溢出。

#include<cmath>
#include<cstdio>
using namespace std;
int t,flag;
long long n;
long long cud(long long x)
{
    return x*x*x;
}
bool check(long long x)
{
    long long l=1,r=pow(x,1.0/3.0)+5;
    while(l<=r)
    {
        long long mid=(l+r)>>1;
        if(cud(mid)>x)    r=mid-1;
        else if(cud(mid)<x)    l=mid+1;
        else    return true;
    }
    return false;
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        flag=0;
        scanf("%lld",&n);
        for(int i=1;cud(i)<n;++i)
        {
            if(check(n-cud(i)))
            {
                flag=1;
                break;
            }
        }
        if(flag)    printf("YES\n");
        else    printf("NO\n");
    }
    return 0;
}

「CF 1490D」Permutation Transformation

Link.

递归建树,照题意模拟即可。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
vector<int> e[110];
int t,n,a[110],dep[110];
int build(int l,int r)
{
    if(l>r)    return -1;
    int root=0,pos=0;
    for(int i=l;i<=r;++i)
    {
        if(a[i]>root)
        {
            root=a[i];
            pos=i;
        }
    }
    if(l^r)
    {
        int one=build(l,pos-1),ano=build(pos+1,r);
        if(~one)    e[root].push_back(one);
        if(~ano)    e[root].push_back(ano);
        return root;
    }
    else    return root;
}
void dfs(int x)
{
    for(int i=0;i<e[x].size();++i)
    {
        int y=e[x][i];
        dep[y]=dep[x]+1;
        dfs(y);
    }
}
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)    scanf("%d",&a[i]);
        dfs(build(1,n));
        for(int i=1;i<=n;++i)    printf("%d ",dep[a[i]]);
        printf("\n");
        for(int i=1;i<=n;++i)
        {
            dep[i]=0;
            e[i].clear();
        }
    }
    return 0;
}

「CF 1490E」Accidental Victory

Link.

贪心,记录个 id 后排序(看代码吧)。

#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
vector<int> ans;
pair<long long,int> a[200010];
int t,n;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%lld",&a[i].first);
            a[i].second=i;
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;++i)    a[i].first+=a[i-1].first;
        ans.push_back(a[n].second);
        for(int i=n-1;i>=1;--i)
        {
            if(a[i].first>=a[i+1].first-a[i].first)    ans.push_back(a[i].second);
            else    break;
        }
        sort(ans.begin(),ans.end());
        printf("%d\n",(int)ans.size());
        for(int i=0;i<ans.size();++i)    printf("%d ",ans[i]);
        printf("\n");
        ans.clear();
        for(int i=1;i<=n;++i)    a[i]=make_pair(0,0);
    }
    return 0;
}

「CF 1490F」Equalize the Array

Link.

统计出现次数和出现次数的出现次数,然后根号模拟取 $\min$。

#include<map>
#include<cstdio>
#include<algorithm>
using namespace std;
const int INF=1e9;
map<int,int> one,ano;
int t,n,a[200010],ans;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i)
        {
            scanf("%d",&a[i]);
            ++one[a[i]];
        }
        for(map<int,int>::iterator now=one.begin();now!=one.end();++now)    ++ano[now->second];
        ans=INF;
        int l=0,r=n,c=one.size();
        for(map<int,int>::iterator now=ano.begin();now!=ano.end();++now)
        {
            ans=min(ans,l+r-c*now->first);
            l+=now->first*now->second;
            r-=now->first*now->second;
            c-=now->second;
        }
        printf("%d\n",ans);
        one.clear();
        ano.clear();
    }
    return 0;
}

「CF 1490G」Old Floppy Drive

Link.

denote for $S$ of the sum of all elements,for $pre$ of the prefix sum of the origin sequence。

首先判断原 $pre$ 里面有没有 $x$,这个搞个 std::map 就有了。

when $S\le0\and\max\{pre_{i}\}<x$ the answer doesn't exist.

if $S\ge0\and\not\exists i,s.t.pre_{i}=x$:此时先把 $x:=x\bmod S$,然后就查 std::map

但是你会发现这样做写起来非常麻烦,可能需要手写平衡树。

于是你发现读错了题,是 $\ge x$ 不是 $=x$ (日你 horse)。

然后负数直接不存进 $pre$ 然后开两个 std::vector 二分就好了。

#include<vector>
#include<cstdio>
#include<algorithm>
using namespace std;
const long long INF=1e18;
vector<long long> onepre;
vector<int> anopre;
long long x,S,mx,len;
int t,n,m;
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        mx=-INF;
        S=0;
        scanf("%d %d",&n,&m);
        for(int i=1;i<=n;++i)
        {
            scanf("%lld",&x);
            S+=x;
            if(onepre.empty()||S>*(prev(onepre.end())))
            {
                onepre.push_back(S);
                anopre.push_back(i-1);
            }
            mx=max(S,mx);
        }
//        printf("-------------------------\n");
//        printf("onemp area:\n");
//        for(auto now:onemp)
//        {
//            printf("    preval=%lld ; preval appearing position=",now.first);
//            for(auto won:now.second)    printf("%d ",won);
//            printf("\n");
//        }
//        printf("\nanomp area:\n");
//        for(auto now:anomp)
//        {
//            printf("[preval=%lld boolean=%d]\n",now.first,now.second);
//        }
//        printf("-------------------------\n");
        while(m--)
        {
//            int minuser=0;
            scanf("%lld",&x);
            if(lower_bound(onepre.begin(),onepre.end(),x)!=onepre.end())    printf("%d ",anopre[lower_bound(onepre.begin(),onepre.end(),x)-onepre.begin()]);
            else if(S<=0)    printf("-1 ");
            else
            {
//                minuser=((x%S)==0);
                len=(mx<x)?((x-mx+S-1)/S):0;
//                printf("(%lld %lld %lld %lld)",x,S,x%S,x/S);
                printf("%lld ",(lower_bound(onepre.begin(),onepre.end(),x%S)==onepre.end())?(-1):(len*n+anopre[lower_bound(onepre.begin(),onepre.end(),x-len*S)-onepre.begin()])/*((((x%S)==0)?(0):(anopre[lower_bound(onepre.begin(),onepre.end(),x%S)-onepre.begin()]))+(int)(x/S)*len-minuser)*/);
            }
        }
        printf("\n");
        onepre.clear();
        anopre.clear();
    }
    return 0;
}