牛客网暑期ACM多校训练营(第一场

补得好辛苦QAQ,不过终于补完了。。
A Monotonic Matrix
A题博主是打表找出规律来的,稍后会把详解贴上来。
找出来的规律为:C(m+n,n)*C(m+n+1,n)/(n+1)
找到规律就好办了,直接预处理出阶乘及阶乘的逆元及1到maxn的逆元就行了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=2005;
const int mod=1e9+7;
long long tab1[maxn],tab2[maxn];

long long extgcd(long long a,long long b,long long &x,long long &y)
{
    if(b==0){x=1;y=0;return a;}
    long long d=extgcd(b,a%b,x,y);
    long long t=x;x=y;y=t-a/b*y;
    return d;
}

long long mod_reverse(long long a,long long p)
{
    long long x,y;
    long long d=extgcd(a,p,x,y);
    if(d==1)return (x%p+p)%p;
    return -1;
}

void init()
{
    tab1[1]=1;
    tab2[1]=mod_reverse(1,mod);
    for(int i=2;i<maxn;i++)
        tab1[i]=tab1[i-1]*i%mod,tab2[i]=mod_reverse(tab1[i],mod);
    tab2[0]=1;

}

int C(int a,int b)
{
    return 1LL*tab1[a]*tab2[b]%mod*tab2[a-b]%mod;
}

int inv[maxn];
void invTable(int n,int p)
{
    inv[1]=1;
    for(int i=2;i<=n;i++)
    {
        inv[i]=1LL*(p-p/i)*inv[p%i]%p;
    }
}

int main()
{
    init();
    invTable(1005,mod);
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        //cout<<C(m+n,n)<<endl;
        //cout<<C(m+n+1,n)<<endl;
        //cout<<inv[n+1]<<endl;
        printf("%lld\n",1LL*C(m+n,n)*C(m+n+1,n)%mod*inv[n+1]%mod);
    }
    return 0;

}

B Symmetric Matrix
B题我们很容易想到邻接矩阵,也就是每个点都连有两条边,可以有重边,但不能有自环。
我们设dp[n]为n个点能构成的方案数。
当我们在添加一个点进来时,如果只从中取一个点和它组成环,那么这个点有n-1种取法,剩下的n-2个点合法方案已经求出。
所以方案数为(n-1)*f(n-2)
推广到一般情况,当我们取k个点,剩下的点与新点组成环,旧点有C(n-1,k),剩下的点与新点组成的环的方案数为(n-1-k)!种,但考虑对称性需要除以2,又考虑只取一个点的时候不需要考虑对称性,所以把这种情况单独拿出来。当然也可以取出0个。
那么化简后的公式为:
f(n)=(n1)f(n2)+n3x=0(n1)!f(x)2x! f ( n ) = ( n − 1 ) ∗ f ( n − 2 ) + ∑ x = 0 n − 3 ( n − 1 ) ! ∗ f ( x ) 2 ∗ x !

这里有个讨厌的求和,我们可以将其化为递推式。
g(n)=(n1)!2n3x=0f(x)x! g ( n ) = ( n − 1 ) ! 2 ∑ x = 0 n − 3 f ( x ) x !
那么 g(n+1)=n!2n3x=0f(x)x!+n(n1)f(n2)2 g ( n + 1 ) = n ! 2 ∑ x = 0 n − 3 f ( x ) x ! + n ∗ ( n − 1 ) ∗ f ( n − 2 ) 2
,再化简即可得到g(n+1)与g(n)的关系
所以 g(n)=(n1)g(i1)+(n1)(n2)f(n3)2 g ( n ) = ( n − 1 ) ∗ g ( i − 1 ) + ( n − 1 ) ( n − 2 ) ∗ f ( n − 3 ) 2

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int f[maxn],g[maxn];
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        if(m==1)
        {
            puts("0");
            continue;
        }
        f[1]=0;
        f[2]=1;
        f[3]=1;
        long long sum=1;
        g[3]=1;
        for(int i=4;i<=n;i++)
        {
            g[i]=(1LL*(i-1)*g[i-1]%m+1LL*(i-1)*(i-2)/2%m*f[i-3]%m)%m;
            f[i]=(1LL*(i-1)*f[i-2]%m+g[i])%m;
        }
        //cout<<g[4]<<endl;
        //+------cout<<f[4]<<endl;
        printf("%d\n",f[n]);
    }
    return 0;
}

D Two Graphs
由于n只有8,所以我们可以枚举所有的映射,根据所映射对应的点之间的边集来作为判断依据,这里注意不能用映射对应的点来作为判断依据,因为就算点选的是一样的,也可以选不同的边来称为同构图。

#include<bits/stdc++.h>
using namespace std;
set<vector<int>>S;
vector<int>V[10];
int mp2[10][10];
int bijection[10];
bool vis[10];
int n,m1,m2;

bool check()
{
    for(int i=1;i<=n;i++)if(V[i].size())
    {
        for(int j=0;j<V[i].size();j++)
        {
            int v=V[i][j];
            if(!mp2[bijection[i]][bijection[v]])
                return 0;
        }
    }
    return 1;
}

void solve()
{
    vector<int>tmp(m2);
    for(int i=0;i<m2;i++)tmp[i]=0;
    for(int i=1;i<=n;i++)if(V[i].size())
    {
        for(int j=0;j<V[i].size();j++)
        {
            int v=V[i][j];
            int idx=mp2[bijection[i]][bijection[v]];
            tmp[idx-1]=1;
        }
    }
    S.insert(tmp);
}


void dfs(int d)
{
    if(d==n+1)
    {
        if(check())
            solve();
        return;
    }
    for(int i=1;i<=n;i++)if(!vis[i])
    {
        vis[i]=1;
        bijection[d]=i;
        dfs(d+1);
        vis[i]=0;
    }
}
int main()
{

    while(scanf("%d %d %d",&n,&m1,&m2)==3)
    {
        memset(mp2,0,sizeof(mp2));
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=n;i++)V[i].clear();
        S.clear();
        int u,v;
        for(int i=1;i<=m1;i++)
        {
            scanf("%d %d",&u,&v);
            V[u].push_back(v);
            V[v].push_back(u);
        }
        for(int i=1;i<=m2;i++)
        {
            scanf("%d %d",&u,&v);
            mp2[u][v]=mp2[v][u]=i;
        }

        dfs(1);
        printf("%d\n",S.size());
    }
    return 0;
}

E Removal
设dp[i][j] 为到i位置已经删除j个数的不同串个数,在转移时,我们可以枚举下一个数是k,那么就转移到了next[i][k] 这个位置,记忆化搜索就完事了。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
const int mod=1e9+7;
int nxt[maxn][15];
int now[15];
int dp[maxn][15];
int n,m,k;
int a[maxn];
int dfs(int now,int d)
{
    if(d==m)return 1;
    if(now==n)
        return 0;
    if(dp[now][d]!=-1)return dp[now][d];
    int res=0;
    for(int i=1;i<=k;i++)
    {
        int nxtidx=nxt[now][i];
        if(nxtidx==-1)continue;
        int tmp=d+nxtidx-now-1;
        if(tmp>m)continue;
        res=(res+dfs(nxtidx,tmp))%mod;
    }
    if(d+n-now==m)res=(res+1)%mod;
    return dp[now][d]=res;
}

int main()
{

    while(~scanf("%d %d %d",&n,&m,&k))
    {
        memset(dp,-1,sizeof(dp));
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=1;i<=k;i++)now[i]=-1;
        for(int i=n;i>=0;i--)
        {
            for(int j=1;j<=k;j++)
                nxt[i][j]=now[j];
            now[a[i]]=i;
        }
        dfs(0,0);
        printf("%d\n",dp[0][0]);
    }
}

F Sum of Maximum
这题想清楚后就会发现很显然,做法也十分套路。
每个数都有自己的最大值,首先我们将a排序,对于a[i-1]!=a[i],我们考虑一下a[i-1]+1到a[i]这个区间的每个数对答案的贡献。
设这个数为x,对于最大值小于x所有的数,它们可以随便取,那么它们提供的方案数为 i1j=1aj ∏ j = 1 i − 1 a j ,记为now。
对于最大值不小于x的那些数,他们只能在1到x中取,并且要保证至少有一个数为x。那么我们倒过来想就行了总方案数减一个都没有的方案数。也就是 xni+1(x1)ni+1 x n − i + 1 − ( x − 1 ) n − i + 1 ,记为 f(x) f ( x ) .
所以x对答案的贡献为now*f(x)*x.
那么这段区间对答案的贡献为
aix=ai1+1nowf(x)x ∑ x = a i − 1 + 1 a i n o w ∗ f ( x ) ∗ x .
化简为 nowaix=ai1+1x(xni+1(x1)ni+1) n o w ∗ ∑ x = a i − 1 + 1 a i x ∗ ( x n − i + 1 − ( x − 1 ) n − i + 1 )
我们设 f(x)=x(xni+1(x1)ni+1) f ( x ) = x ∗ ( x n − i + 1 − ( x − 1 ) n − i + 1 )
套路来了。我们观察这个式子,实际上它就是一个幂为n-i+2的多项式,我们想得到这个多项式的某个区间的和,而他的和的函数的最大幂肯定不超过n-i+2,所以我们可以枚举n-i+2个点,计算出n-i+2 f(x) f ( x ) 个点出来,再利用拉格朗日插值把它的和的函数计算出来。这样就做出来了。
有空研究一下这个模板的奥秘,现在先贴出来吧。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;

namespace polysum
{
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    const int D=2010;
    ll a[D],f[D],g[D],p[D],p1[D],p2[D],b[D],h[D][2],C[D];
    ll powmod(ll a,ll b){ll res=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    ll calcn(int d,ll *a,ll n) { // a[0].. a[d]  a[n]
        if (n<=d) return a[n];
        p1[0]=p2[0]=1;
        rep(i,0,d+1) {
            ll t=(n-i+mod)%mod;
            p1[i+1]=p1[i]*t%mod;
        }
        rep(i,0,d+1) {
            ll t=(n-d+i+mod)%mod;
            p2[i+1]=p2[i]*t%mod;
        }
        ll ans=0;
        rep(i,0,d+1) {
            ll t=g[i]*g[d-i]%mod*p1[i]%mod*p2[d-i]%mod*a[i]%mod;
            if ((d-i)&1) ans=(ans-t+mod)%mod;
            else ans=(ans+t)%mod;
        }
        return ans;
    }
    void init(int M) {
        f[0]=f[1]=g[0]=g[1]=1;
        rep(i,2,M+5) f[i]=f[i-1]*i%mod;
        g[M+4]=powmod(f[M+4],mod-2);
        per(i,1,M+4) g[i]=g[i+1]*(i+1)%mod;
    }
    ll polysum(ll m,ll *a,ll n) { // a[0].. a[m] \sum_{i=0}^{n-1} a[i]
        ll b[D];
        for(int i=0;i<=m;i++) b[i]=a[i];
        b[m+1]=calcn(m,b,m+1);
        rep(i,1,m+2) b[i]=(b[i-1]+b[i])%mod;
        return calcn(m+1,b,n-1);
    }
    ll qpolysum(ll R,ll n,ll *a,ll m) { // a[0].. a[m] \sum_{i=0}^{n-1} a[i]*R^i
        if (R==1) return polysum(n,a,m);
        a[m+1]=calcn(m,a,m+1);
        ll r=powmod(R,mod-2),p3=0,p4=0,c,ans;
        h[0][0]=0;h[0][1]=1;
        rep(i,1,m+2) {
            h[i][0]=(h[i-1][0]+a[i-1])*r%mod;
            h[i][1]=h[i-1][1]*r%mod;
        }
        rep(i,0,m+2) {
            ll t=g[i]*g[m+1-i]%mod;
            if (i&1) p3=((p3-h[i][0]*t)%mod+mod)%mod,p4=((p4-h[i][1]*t)%mod+mod)%mod;
            else p3=(p3+h[i][0]*t)%mod,p4=(p4+h[i][1]*t)%mod;
        }
        c=powmod(p4,mod-2)*(mod-p3)%mod;
        rep(i,0,m+2) h[i][0]=(h[i][0]+h[i][1]*c)%mod;
        rep(i,0,m+2) C[i]=h[i][0];
        ans=(calcn(m,C,n)*powmod(R,n)-c)%mod;
        if (ans<0) ans+=mod;
        return ans;
    }

}


ll pow2(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int main()
{
    int t,n,i,j;
    ll ans,a[1111],now,b[1111];
    polysum::init(1010);
    while(~scanf("%d",&n))
    {
        for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
        ans=0;
        sort(a+1,a+1+n);
        a[0]=0;
        now=1;
        for(int i=1;i<=n;i++)
        {
            if(a[i]==a[i-1])
            {
                (now*=a[i])%=mod;
                continue;
            }
            b[0]=0;
            for(j=1;j<=n-i+1;j++)
                b[j]=1LL*j*(((pow2(j,n-i+1)-pow2(j-1,n-i+1)%mod)+mod)%mod)%mod;
            ll tmp=((polysum::polysum(n-i+1,b,a[i]+1)-polysum::polysum(n-i+1,b,a[i-1]+1))%mod+mod)%mod;
            (ans+=tmp*now%mod)%=mod;
            (now*=a[i])%=mod;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

H Longest Path
这题重新让我学习到了斜率dp。
首先我们考虑往下走可以得到的最大值(包括自己连向父亲的边),直接dfs即可得到,记为 down(i) d o w n ( i )
up(i)表示该点往上再往下可以得到的最大值,从上往下更新。
up(u)=max(up(fa)+(e(u)e(fa))2) u p ( u ) = m a x ( u p ( f a ) + ( e ( u ) − e ( f a ) ) 2 )
它也可以往上走到父亲再往下走到其他的兄弟结点。
那么 up(u)=max(down(u)+(e(u)e(u)2)) u p ( u ) = m a x ( d o w n ( u ′ ) + ( e ( u ) − e ( u ′ ) 2 ) )
重点就是如何快速得到与父亲相同的点中的最大值,看这个式子很容易想到斜率优化,首先我们将父亲是同一个的点放进一个数组里面,按照它们的边排序,再斜率优化从左到右搞一次,从右到左搞一次就行了。
为啥博主搞错了呢,从左到右由于是最大值,那么是维护一个上凸包,并且斜率是递增的(也就是那个常数),所以减的方向实际是tail,不是front。
而从右到左是最小值,那么维护一个下凸包,而斜率是递减的,所以减的方向还是tail。
所以不要想当然的套模板啊。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<pair<int,int> >G[maxn];
typedef pair<int,int> pii;

long long pow2(long long a)
{
    return a*a;
}
int c[maxn];
long long down[maxn];
void dfs1(int u,int pre)
{
    for(pii x:G[u])if(x.first!=pre)
    {
        int v=x.first,w=x.second;
        c[v]=w;
        dfs1(v,u);
        if(u!=1)down[u]=max(down[u],down[v]+pow2(c[v]-c[u]));
    }
}

long long up[maxn];
int p[maxn];

long long getup(int j,int k)
{
    j=p[j],k=p[k];
    return down[j]+pow2(1LL*c[j])-down[k]-pow2(c[k]);
}

long long getdown(int j,int k)
{
    j=p[j],k=p[k];
    return 2LL*(c[j]-c[k]);
}

long long Cal(int idx,int i)
{
    if(idx==0)return 0;
    idx=p[idx];
    i=p[i];
    return 1LL*down[idx]+pow2(c[i]-c[idx]);
}

bool cmp1(int a,int b)
{
    return c[a]<c[b];
}
int Q[maxn];

void solve(int n)
{
    sort(p+1,p+1+n,cmp1);
    int front=1,tail=0;
    Q[0]=0;
    for(int i=1;i<=n;i++)
    {
        while(front<tail&&getup(Q[tail],Q[tail-1])<getdown(Q[tail],Q[tail-1])*c[p[i]])tail--;
        int idx=Q[tail];
        up[p[i]]=max(up[p[i]],Cal(idx,i));
        while(front<tail&&getup(i,Q[tail])*getdown(Q[tail],Q[tail-1])>getup(Q[tail],Q[tail-1])*getdown(i,Q[tail]))tail--;
        Q[++tail]=i;
    }
    front=1,tail=0;
    Q[0]=0;
    for(int i=n;i>=1;i--)
    {
        while(front<tail&&getup(Q[tail],Q[tail-1])<getdown(Q[tail],Q[tail-1])*c[p[i]])tail--;
        int idx=Q[tail];
        up[p[i]]=max(up[p[i]],Cal(idx,i));
        while(front<tail&&getup(i,Q[tail])*getdown(Q[tail],Q[tail-1])<getup(Q[tail],Q[tail-1])*getdown(i,Q[tail]))tail--;
        Q[++tail]=i;
    }
}
long long ans[maxn];
void dfs2(int u,int pre)
{
    int k=0;
    if(u!=1&&pre!=1)
        up[u]=max(up[u],up[pre]+pow2(c[u]-c[pre]));
    for(pii x:G[u])if(x.first!=pre)
    {
        int v=x.first,w=x.second;
        p[++k]=v;
    }
    solve(k);
    ans[u]=up[u];
    for(pii x:G[u])if(x.first!=pre)
    {
        int v=x.first,w=x.second;
        ans[u]=max(ans[u],down[v]);
        dfs2(v,u);
    }

}

int main()
{
    int N;
    while(~scanf("%d",&N))
    {
        for(int i=1;i<=N;i++)G[i].clear();
        memset(up,0,sizeof(up));
        memset(down,0,sizeof(down));
        memset(ans,0,sizeof(ans));
        int u,v,c;
        for(int i=1;i<N;i++)
        {
            scanf("%d %d %d",&u,&v,&c);
            G[u].push_back(make_pair(v,c));
            G[v].push_back(make_pair(u,c));
        }
        dfs1(1,0);
        dfs2(1,0);
        for(int i=1;i<=N;i++)
            printf("%lld\n",ans[i]);
    }
    return 0;
}

I Substring
求本质不同子串个数。
什么叫本质不同的子串,ab,ac,bc…都是本质相同的子串。我们试想一个串求不同串时,ab,ac都会被算一次,而实际上他们本质是相同的,只是位置上的字符不同罢了。所以我们不妨将abc所有的映射都预处理出来(6个),将原字符串映射成6份,那么ab,ac,bc,ba,ca,cb都会被算进去,再除以6就相当于只算了一次了。
但aa这种只出现一种字符的字符串在这种处理下,只会变成aa,bb,cc三种,所以我们要找到映射后的不同子串个数ans1,和最长的只出现一种字符串的长度ans2,那么答案即为(ans1-3*ans2)/6+ans2.

#include<bits/stdc++.h>
using namespace std;
#define rank rk
const int maxn=50005*6+100;
int ch[maxn];
int cntA[maxn],cntB[maxn],A[maxn],B[maxn],tsa[maxn],SA[maxn],rank[maxn],height[maxn];
int N;
void get_SA()
{
    for(int i=0;i<=200;i++)cntA[i]=0;
    for(int i=1;i<=N;i++)cntA[ch[i]]++;
    for(int i=1;i<=200;i++)cntA[i]+=cntA[i-1];
    for(int i=N;i>=1;i--)SA[cntA[ch[i]]--]=i;
    rank[SA[1]]=1;
    for(int i=2;i<=N;i++)
    {
        rank[SA[i]]=rank[SA[i-1]];
        if(ch[SA[i]]!=ch[SA[i-1]])
            rank[SA[i]]++;
    }

    //cout<<endl;
    for(int step=1;rank[SA[N]]<N;step<<=1)
    {
        for(int i=1;i<=N;i++)cntA[i]=cntB[i]=0;
        for(int i=1;i<=N;i++)
        {
            cntA[A[i]=rank[i]]++;
            cntB[B[i]=(i+step<=N)?rank[i+step]:0]++;
        }
        for(int i=1;i<=N;i++)cntA[i]+=cntA[i-1],cntB[i]+=cntB[i-1];
        for(int i=N;i>=1;i--)tsa[cntB[B[i]]--]=i;
        for(int i=N;i>=1;i--)SA[cntA[A[tsa[i]]]--]=tsa[i];
        rank[SA[1]]=1;
        for(int i=2;i<=N;i++)
        {
            rank[SA[i]]=rank[SA[i-1]];
            if(A[SA[i]]!=A[SA[i-1]]||B[SA[i]]!=B[SA[i-1]])
                rank[SA[i]]++;
        }
    }
}

void get_Height()
{
    int i,j,k=0;
    for(int i=1; i<=N; i++)
    {
        if(k)k--;
        j=SA[rank[i]-1];
        while(ch[i+k]==ch[j+k])k++;
        height[rank[i]]=k;
    }
}
int bij[7][4];
void init()
{
    int cas=0;
    for(int j=0; j<3; j++)
        for(int p=0; p<3; p++)if(p!=j)
                for(int q=0; q<3; q++)if(p!=q&&q!=j)
                    {
                        cas++;
                        bij[cas][0]=j;
                        bij[cas][1]=p;
                        bij[cas][2]=q;
                    }
}
char s[50005];
void getch()
{
    int len=strlen(s+1);
    for(int i=1;i<=6;i++)
    {
        for(int j=1;j<=len;j++)
            ch[++N]=bij[i][s[j]-'a'];
        ch[++N]=3;

    }
    //cout<<endl;
}
int n;
long long get1()
{
    int pre=0;
    long long ans=0;
    //cout<<height[1]<<endl;
    for(int i=1;i<=N;i++)
    {
        ans=ans+n-(SA[i]-1)%(n+1)-min({height[i],pre,n-(SA[i]-1)%(n+1)});
        //cout<<SA[i]<<endl;
        pre=n-(SA[i]-1)%(n+1);
    }

    return ans;
}

long long get2()
{
    long long res=0;
    long long cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(s[i]!=s[i-1])
        {
            res=max(res,cnt);
            cnt=1;
        }
        else
            cnt++;
    }
    res=max(res,cnt);
    return res;
}

int main()
{

    init();
    while(~scanf("%d",&n))
    {
        ch[0]=3;
        N=0;
        scanf("%s",s+1);
        getch();
        get_SA();
        get_Height();
        long long ans1=get1();
        long long ans2=get2();
        //cout<<ans1<<endl;
        //cout<<ans2<<endl;
        printf("%lld\n",(ans1-ans2*3)/6+ans2);
    }
}

J Different Integers
签到题没啥好说的,莫队就完事了。

#include<bits/stdc++.h>
using namespace std;
int len;
const int maxn=1e5+5;
struct Query
{
    int L,R,block;
    int idx;
    Query(int l,int r,int i):L(l),R(r),idx(i)
    {
        block=L/len;
    }
    Query(){}
    bool operator<(const Query &b)const
    {
        if(block!=b.block)return block<b.block;
        return R<b.R;
    }
};

Query q[maxn];
int ans[maxn];
int times[maxn];
int havenum;
int a[maxn];

void insert(int num)
{
    times[num]++;
    if(times[num]==1)havenum++;
}

void erase(int num)
{
    times[num]--;
    if(times[num]==0)havenum--;
}

int main()
{
    int N,Q;
    while(~scanf("%d %d",&N,&Q))
    {
        havenum=0;
        memset(times,0,sizeof(times));
        len=(int)sqrt(N);
        for(int i=1;i<=N;i++)scanf("%d",&a[i]);
        int l,r;
        for(int i=1;i<=Q;i++)
        {
            scanf("%d %d",&l,&r);
            q[i]=Query(l,r,i);
        }
        sort(q+1,q+1+Q);
        int L=1,R=1;
        for(int i=1;i<=N;i++)
            insert(a[i]);
        insert(a[1]);
        for(int i=1;i<=Q;i++)
        {
            Query tmp=q[i];
            while(R<tmp.R)erase(a[R++]);
            while(L>tmp.L)erase(a[L--]);
            while(R>tmp.R)insert(a[--R]);
            while(L<tmp.L)insert(a[++L]);
            ans[tmp.idx]=havenum;
        }
        for(int i=1;i<=Q;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}

补难题好爽,也好烦。继续加油吧。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值