2025多校冲刺省选模拟赛13

2025多校冲刺省选模拟赛13

T1 A. 逆序对 56pts

  • 原题: luogu P5972 [PA 2019] Desant

  • 部分分

    • 56pts :爆搜。
    点击查看代码
    int a[50];
    pair<int,ll>ans[50];
    struct BIT
    {
        int c[50];
        int lowbit(int x)
        {
            return x&(-x);
        }
        void add(int x,int val)
        {
            for(int i=x;i>=1;i-=lowbit(i))  c[i]+=val;
        }
        int getsum(int n,int x)
        {
            int ans=0;
            for(int i=x;i<=n;i+=lowbit(i))  ans+=c[i];
            return ans;
        }
    }B;
    void dfs(int pos,int n,int len,int sum)
    {
        if(pos==n+1)
        {
            if(ans[len].first>sum)  ans[len]=make_pair(sum,1ll);
            else if(ans[len].first==sum)  ans[len].second++;
        }
        else
        {
            B.add(a[pos],1);
            dfs(pos+1,n,len+1,sum+B.getsum(n,a[pos]+1));
            B.add(a[pos],-1);
            dfs(pos+1,n,len,sum);
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("des.in","r",stdin);
        freopen("des.out","w",stdout);
    #endif
        int n,i;
        cin>>n;
        for(i=1;i<=n;i++)  cin>>a[i];
        memset(ans,0x3f,sizeof(ans));
        dfs(1,n,0,0);
        for(i=1;i<=n;i++)  cout<<ans[i].first<<" "<<ans[i].second<<endl;
        return 0;
    }
    
  • 正解

    • 折半搜索瓶颈在于无法快速合并两个区间的答案,没有前途。
    • 考虑状压,设 fi,S 表示 [1,i] 中选出的数的集合为 S 时的逆序对数, O(2n) 的状态数无法接受,需要进一步优化。
    • 观察到对于后续加入 ai+1n 的贡献,我们只关心 (0,ai+1),(ai+1,ai+2),,(an1,an),(an,n+1) 内元素的数量(钦定 ai+1nai+1n 升序排序后的结果)。不妨将每一段内元素的数量作为状态进行转移。由 相关理论 可知和为 n 的若干个数的积最大为 ene ,若必须为正整数则最大值规模大概是 O(3n3)
    • 集合 S 直接作为下标的话需要哈希表进行辅助,不妨直接将每段的长度作为当前段数的进制转成 int 类型的数作为下标,询问时再进行反着解码回去即可。
    • 转移时枚举下一位选或不选刷表转移即可,注意因两段合成一段的下标移位问题。
    点击查看代码
    int a[50],suf[50][50],d[50],c[50][50];
    vector<pair<int,ll> >f[50];
    pair<int,ll> sx_min(pair<int,ll> a,pair<int,ll> b)
    {
        if(a.first==b.first)  return make_pair(a.first,a.second+b.second);
        else  return (a.first<b.first)?a:b;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("des.in","r",stdin);
        freopen("des.out","w",stdout);
    #endif
        int n,id,tmp,sum,i,j,k,w;
        cin>>n;  a[n+1]=n+1;
        for(i=1;i<=n;i++)  cin>>a[i];
        for(i=0;i<=n;i++)
        {
            for(j=i+1;j<=n+1;j++)  
            {
                suf[i][0]++;  suf[i][suf[i][0]]=a[j];
            }
            sort(suf[i]+1,suf[i]+1+suf[i][0]);
            for(j=w=1;j<=suf[i][0];j++)
            {
                c[i][j]=w;  w*=((j==1)?suf[i][j]:(suf[i][j]-suf[i][j-1]));
            }
            f[i].resize(w);  fill(f[i].begin(),f[i].end(),make_pair(0x3f3f3f3f,0));
        }
        f[0][0]=make_pair(0,1);
        for(i=0;i<=n-1;i++)
        {
            id=0;
            for(j=1;j<=suf[i][0];j++)  if(suf[i][j]==a[i+1])  id=j;
            for(j=0;j<f[i].size();j++)
            {
                w=j;  sum=tmp=0;
                for(k=suf[i][0];k>=1;k--)
                {
                    d[k]=w/c[i][k];  w%=c[i][k];
                    if(k>=id+1)  sum+=d[k];
                    if(k==id||k==id+1)  tmp+=d[k]*c[i+1][id];// 两段合成一段
                    else  tmp+=d[k]*c[i+1][k-(k>=id+2)];//移位
                }
                f[i+1][tmp]=sx_min(f[i+1][tmp],f[i][j]);
                tmp+=c[i+1][id];// 段内元素数量 +1
                f[i+1][tmp]=sx_min(f[i+1][tmp],make_pair(f[i][j].first+sum,f[i][j].second));
            }
        }
        for(i=1;i<=n;i++)  cout<<f[n][i].first<<" "<<f[n][i].second<<endl;
        return 0;
    }
    

T2 B. 网格图 100pts

  • n=3 时做法同 2025多校冲刺省选模拟赛9 T2 B.雪雀

  • n=1 时手推下,对答案的贡献系数为 2((m1)+(mi)(i1))

  • n=2 时类似 n=3 进行分治,但 DP 转移简单了不少。

    点击查看代码
    const ll p=1000000007;
    ll a[4][200010],L[4][4][200010],R[4][4][200010],d[600010],n,m,ans=0;
    struct node
    {
        ll x,y,val,op;
        bool operator < (const node &another) const
        {
            return (x==another.x)?(op<another.op):(x<another.x);
        }
    };
    vector<node>q;
    struct BIT
    {
        ll c[2][600010];
        void clear()
        {
            for(ll i=1;i<=d[0];i++)  c[0][i]=c[1][i]=0;
        }
        ll lowbit(ll x)
        {
            return (x&(-x));
        }
        void add(ll m,ll x,ll val1,ll val2)
        {
            for(ll i=x;i<=m;i+=lowbit(i))
            {
                c[0][i]=(c[0][i]+val1)%p;
                c[1][i]=(c[1][i]+val2)%p;
            }
        }
        ll getsum(ll x,ll val)
        {
            ll sum1=0,sum2=0;
            for(ll i=x;i>=1;i-=lowbit(i))
            {
                sum1=(sum1+c[0][i])%p;
                sum2=(sum2+c[1][i])%p;
            }
            return (sum1+sum2*val%p)%p;
        }
    }T;
    void work()
    {
        T.clear();  sort(q.begin(),q.end());
        d[0]=0;
        for(ll i=0;i<q.size();i++)  d[++d[0]]=q[i].y;
        sort(d+1,d+1+d[0]);  d[0]=unique(d+1,d+1+d[0])-(d+1);
        for(ll i=0;i<q.size();i++)
        {
            q[i].y=lower_bound(d+1,d+1+d[0],q[i].y)-d;
            if(q[i].op==0)  T.add(d[0],q[i].y,q[i].val%p,1);
            else  ans=(ans+T.getsum(q[i].y,q[i].val%p))%p;
        }
    }
    struct Subtest1
    {
        ll solve()
        {
            ll ans=0;
            for(ll i=1;i<=m;i++)  ans=(ans+a[1][i]*2%p*((m-1)%p+(m-i)%p*(i-1)%p)%p)%p;
            return ans;
        }
    }S1;
    struct Subtest2
    {
        void dp(ll l,ll r,ll mid)
        {
            L[1][1][mid]=a[1][mid];  L[1][2][mid]=a[1][mid]+a[2][mid];
            L[2][1][mid]=a[1][mid]+a[2][mid];  L[2][2][mid]=a[2][mid];
            for(ll op=1;op<=2;op++)
            {
                for(ll i=mid-1;i>=l;i--)
                {
                    L[op][1][i]=min({L[op][1][i+1]+a[1][i],L[op][2][i+1]+a[2][i]+a[1][i]});
                    L[op][2][i]=min({L[op][2][i+1]+a[2][i],L[op][1][i+1]+a[2][i]+a[1][i]});
                }
            }
            mid++;
            R[1][1][mid]=a[1][mid];  R[1][2][mid]=a[1][mid]+a[2][mid];
            R[2][1][mid]=a[1][mid]+a[2][mid];  R[2][2][mid]=a[2][mid];
            for(ll op=1;op<=2;op++)
            {
                for(ll i=mid+1;i<=r;i++)
                {
                    R[op][1][i]=min({R[op][1][i-1]+a[1][i],R[op][2][i-1]+a[2][i]+a[1][i]});
                    R[op][2][i]=min({R[op][2][i-1]+a[2][i],R[op][1][i-1]+a[2][i]+a[1][i]});
                }
            }
        }
        void solve(ll l,ll r)
        {
            if(l==r)
            {
                ans=(ans+a[1][l]+a[2][l])%p;
                return;
            }
            ll mid=(l+r)/2;
            solve(l,mid);  solve(mid+1,r);
            dp(l,r,mid);
            for(ll z=1;z<=2;z++)
            {
                q.clear();
                ll x=((z==1)?2:1);
                for(ll op=1;op<=2;op++)
                {
                    for(ll i=l;i<=mid;i++)  q.push_back((node){L[z][op][i]-L[x][op][i]+(z!=1),0,L[z][op][i],0});
                    for(ll i=mid+1;i<=r;i++)  q.push_back((node){R[x][op][i]-R[z][op][i],0,R[z][op][i],1});
                }	
                work();
            }
        }
    }S2;
    struct Subtest3
    {
        ll f[200010],g[200010];
        void init()
        {
            f[0]=g[m+1]=0x3f3f3f3f3f3f3f3f;
            for(ll i=1;i<=m;i++)  f[i]=min(f[i-1],a[2][i])+a[1][i]+a[3][i];
            for(ll i=m;i>=1;i--)  g[i]=min(g[i+1],a[2][i])+a[1][i]+a[3][i];
        }
        void dp(ll l,ll r,ll mid)
        {
            L[1][1][mid]=a[1][mid];  L[1][2][mid]=a[1][mid]+a[2][mid];  L[1][3][mid]=min(f[mid],g[mid]);
            L[2][1][mid]=a[1][mid]+a[2][mid];  L[2][2][mid]=a[2][mid];  L[2][3][mid]=a[2][mid]+a[3][mid];
            L[3][1][mid]=min(f[mid],g[mid]);  L[3][2][mid]=a[2][mid]+a[3][mid];  L[3][3][mid]=a[3][mid];
            for(ll op=1;op<=3;op++)
            {
                for(ll i=mid-1;i>=l;i--)
                {
                    L[op][1][i]=min({L[op][1][i+1]+a[1][i],L[op][2][i+1]+a[2][i]+a[1][i],L[op][3][i+1]+f[i]});
                    L[op][3][i]=min({L[op][1][i+1]+f[i],L[op][2][i+1]+a[2][i]+a[3][i],L[op][3][i+1]+a[3][i]});
                    L[op][2][i]=min({L[op][1][i]+a[2][i],L[op][2][i+1]+a[2][i],L[op][3][i]+a[2][i]});
                }
            }
            mid++;
            R[1][1][mid]=a[1][mid];  R[1][2][mid]=a[1][mid]+a[2][mid];  R[1][3][mid]=min(f[mid],g[mid]);
            R[2][1][mid]=a[1][mid]+a[2][mid];  R[2][2][mid]=a[2][mid];  R[2][3][mid]=a[2][mid]+a[3][mid];
            R[3][1][mid]=min(f[mid],g[mid]);  R[3][2][mid]=a[2][mid]+a[3][mid];  R[3][3][mid]=a[3][mid];
            for(ll op=1;op<=3;op++)
            {
                for(ll i=mid+1;i<=r;i++)
                {
                    R[op][1][i]=min({R[op][1][i-1]+a[1][i],R[op][2][i-1]+a[2][i]+a[1][i],R[op][3][i-1]+g[i]});
                    R[op][3][i]=min({R[op][1][i-1]+g[i],R[op][2][i-1]+a[2][i]+a[3][i],R[op][3][i-1]+a[3][i]});
                    R[op][2][i]=min({R[op][1][i]+a[2][i],R[op][2][i-1]+a[2][i],R[op][3][i]+a[2][i]});
                }
            }
        }
        void solve(ll l,ll r)
        {
            if(l==r)
            {
                ans=(ans+a[1][l]+2*a[2][l]+a[3][l]+min(f[l],g[l]))%p;
                return;
            }
            ll mid=(l+r)/2;
            solve(l,mid);  solve(mid+1,r);
            dp(l,r,mid);
            for(ll z=1;z<=3;z++)
            {
                q.clear();
                ll x=((z==1)?2:1),y=((z==3)?2:3);
                for(ll op=1;op<=3;op++)
                {
                    for(ll i=l;i<=mid;i++)  q.push_back((node){L[z][op][i]-L[x][op][i]+(z!=1),L[z][op][i]-L[y][op][i]+(z==3),L[z][op][i],0});
                    for(ll i=mid+1;i<=r;i++)  q.push_back((node){R[x][op][i]-R[z][op][i],R[y][op][i]-R[z][op][i],R[z][op][i],1});
                }	
                work();
            }
        }
    }S3;
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("grid.in","r",stdin);
        freopen("grid.out","w",stdout);
    #endif
        cin>>n>>m;
        for(ll i=1;i<=n;i++)
        {
            for(ll j=1;j<=m;j++)  cin>>a[i][j];
        }
        if(n==1)  cout<<S1.solve();
        if(n==2)
        {
            S2.solve(1,m);  cout<<ans*2%p<<endl;
        }
        if(n==3)
        {
            S3.init();
            S3.solve(1,m);  cout<<ans*2%p<<endl;
        }
        return 0;
    }
    

T2 HZTG2487. 选拔 100pts

  • 部分分

    • 10pts :输出大样例。
    • 30pts :预处理所有字符串的哈希值。
    点击查看代码
    #include<bits/extc++.h>
    using namespace __gnu_pbds;
    const ll mod=1000003579,base=13331;
    struct node
    {
        int nxt,to,w;
    }e[60010];
    int head[30010],hsh[30010],cnt=0;
    gp_hash_table<int,bool>vis;
    char s[30010];
    void add(int u,int v,int w)
    {
        cnt++;  e[cnt]=(node){head[u],v,w};  head[u]=cnt;
    }
    int sx_hash(char s[],int len)
    {
        int ans=0;
        for(int i=1;i<=len;i++)  ans=(1ll*ans*base%mod+s[i])%mod;
        return ans;
    }
    void dfs(int x,int fa)
    {
        vis[hsh[x]]=1;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa)
            {
                hsh[e[i].to]=(1ll*hsh[x]*base%mod+e[i].w)%mod;
                dfs(e[i].to,x);
            }
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("selection.in","r",stdin);
        freopen("selection.out","w",stdout);
    #endif
        int n,m,u,v,i;
        char c;
        cin>>n;
        if(n==30000)
        {
            cout<<"NO\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nNO\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nNO\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nNO\nYES\nNO\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nNO\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nNO\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nYES\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nYES\nYES\nYES\nNO\nNO\nNO\nNO\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nNO\nNO\nNO\nYES\nYES\nYES\nYES\nYES\nYES\nYES\nNO\nYES\nNO\nNO\nNO\nYES\n";
        }
        else
        {
            for(i=1;i<=n-1;i++)
            {
                cin>>u>>v>>c;
                add(u,v,c);  add(v,u,c);
            }
            for(i=1;i<=n;i++)
            {
                hsh[i]=0;  dfs(i,0);
            }
            cin>>m;
            for(i=1;i<=m;i++)
            {
                cin>>(s+1);
                cout<<((vis.find(sx_hash(s,strlen(s+1)))==vis.end())?"NO":"YES")<<endl;
            }
        }
        return 0;
    }
    
    • 100pts :每组询问按位遍历所有字符串。
    点击查看代码
    struct node
    {
        int nxt,to;
        char w;
    }e[60010];
    int head[30010],cnt=0,len,f[30010],g[30010],limit;
    char s[30010];
    void add(int u,int v,char w)
    {
        cnt++;  e[cnt]=(node){head[u],v,w};  head[u]=cnt;
    }
    bool dfs(int x,int fa,int tot)
    {
        if(tot==len+1)  return true;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa&&e[i].w==s[tot]&&dfs(e[i].to,x,tot+1)==true)
            {
                return true;
            }
        }
        return false;
    }
    void dfs(int x,int fa)
    {
        f[x]=g[x]=0;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=fa)
            {
                dfs(e[i].to,x);
                if(f[e[i].to]+1>f[x])
                {
                    g[x]=f[x];
                    f[x]=f[e[i].to]+1;
                }
                else  g[x]=max(g[x],f[e[i].to]+1);
            }
        }
        limit=max(limit,f[x]+g[x]);
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("selection.in","r",stdin);
        freopen("selection.out","w",stdout);
    #endif
        int n,m,u,v,flag,i,j;
        char c;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>u>>v>>c;
            add(u,v,c);  add(v,u,c);
        }
        dfs(1,0);
        cin>>m;
        for(i=1;i<=m;i++)
        {
            cin>>(s+1);  len=strlen(s+1);  flag=0;
            for(j=1;j<=n&&flag==0&&len<=limit;j++)
            {
                if(dfs(j,0,1)==true)  flag=1;
            }
            cout<<((flag==0)?"NO":"YES")<<endl;
        }
        return 0;
    }
    
  • 正解

    • 观察到模式串的出现方式一定是一条从下到上的路径和一条从上到下的路径拼起来。
    • fx,i,j 表示从下到上走到 x 能否匹配 ti,[1,j]gx,i,j 表示从上到下从 x 出发能否匹配 ti,[j,|ti|] 。将所有模式串用特殊字符隔开后用 bitset 加速即可。
    • 一种方便的代码实现是每两个模式串之间用两个特殊字符隔开分别作为前一个串的末尾和后一个串的开头辅助转移(即某条路径为空的情况),但空间开不下。单独处理路径为空的情况即可。
    • DFS 的途中转移会爆递归栈。
    点击查看代码
    struct node
    {
        int nxt,to,w;
    }e[60010];
    int head[30010],l[30010],r[30010],fa[30010],pos[30010],w[30010],tot=0,cnt=0;
    bitset<60010>f[30010],g[30010],id[30],ans[3];
    char s[60010],t[30010];
    void add(int u,int v,int w)
    {
        cnt++;  e[cnt]=(node){head[u],v,w};  head[u]=cnt;
    }
    void dfs(int x,int father)
    {
        fa[x]=father;
        tot++;  pos[tot]=x;
        for(int i=head[x];i!=0;i=e[i].nxt)
        {
            if(e[i].to!=father)
            {
                w[e[i].to]=e[i].w;
                dfs(e[i].to,x);
            }
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("selection.in","r",stdin);
        freopen("selection.out","w",stdout);
    #endif
        int n,m,len=0,_len,u,v,flag,i,j;
        char c;
        cin>>n;
        for(i=1;i<=n-1;i++)
        {
            cin>>u>>v>>c;
            add(u,v,c-'a'+1);  add(v,u,c-'a'+1);
        }
        dfs(1,0);
        cin>>m;
        for(i=1;i<=m;i++)
        {
            cin>>(t+1);  _len=strlen(t+1);
            len++;  s[len]='#';
            l[i]=len+1;
            for(j=1;j<=_len;j++)
            {
                len++;  s[len]=t[j];
            }
            r[i]=len;
        }
        for(i=1;i<=len;i++)  id[(s[i]=='#')?27:s[i]-'a'+1][i]=1;
        for(i=1;i<=n;i++)  f[i]=g[i]=id[27];
        for(i=n;i>=1;i--)
        {
            u=pos[i];  v=fa[u];
            ans[1]|=f[u];  ans[2]|=g[u];
            ans[0]|=(f[u]<<1)&id[w[u]]&(g[v]>>1);
            ans[0]|=(f[v]<<1)&id[w[u]]&(g[u]>>1);
            f[v]|=(f[u]<<1)&id[w[u]];
            g[v]|=(g[u]>>1)&id[w[u]];
        }
        for(i=1;i<=m;i++)
        {
            flag=ans[1][r[i]]|ans[2][l[i]];
            for(j=l[i];j<=r[i];j++)  flag|=ans[0][j];
            cout<<(flag==0?"NO":"YES")<<endl;
        }
        return 0;
    }
    

T3 C. 种苹果 15pts

  • 原题: LibreOJ 6039. 「雅礼集训 2017 Day5」珠宝 /「NAIPC2016」Jewel Thief

  • 部分分

    • 15pts :暴力进行背包。
    点击查看代码
    const ll p=998244353;
    ll f[1500010],b[300010],c[300010];
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("apple.in","r",stdin);
        freopen("apple.out","w",stdout);
    #endif
        ll n,m=0,ans=0,base=20201205,i,j;
        scanf("%lld",&n);
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&b[i]);  m+=b[i];
        }
        for(i=1;i<=n;i++)
        {
            scanf("%lld",&c[i]);
            for(j=m;j>=b[i];j--)  f[j]=max(f[j],f[j-b[i]]+c[i]);
        }
        for(i=1;i<=m+1;i++)  f[i-1]%=p;
        for(i=1;i<=m+1;i++,base=base*20201205%p)  ans=(ans+base*f[i-1]%p)%p;
        printf("%lld\n",ans);
        return 0;
    }
    
  • 正解

    • 对同一重量的价值降序排序,内部选择时一定是一段前缀。
    • fi,j 表示仅考虑重量 [1,i] 时重量 j 时的最大价值,状态转移方程为 fi,j=max{fi1,jik+si,k} ,其中 si 为重量为 i 的前缀和。
    • 观察到 j(jik)(modi) ,考虑按照余数进行分组,则有 fi,j=maxjk(modi),kj{fi1,k+w(j,k)} ,其中 w(j,k)=si,jki
    • 进一步地,观察到转移过程中具有决策单调性。具体地,若 fi1,k+w(j,k)<fi1,k+w(j,k),k<k 则后续过程 k 一定不如 k 优,考虑新加入的长度为 jji 的贡献 si,jkisi,jkisi,jkisi,jki
    • 分治法加速即可。
    点击查看代码
    const ll p=998244353;
    ll f[1500010],g[1500010],tmp[1500010],sum[1500010],x[1500010],y[1500010];
    vector<ll>v[10];
    void solve(ll l,ll r,ll x,ll y)
    {
        if(l>r)  return;
        ll mid=(l+r)/2,opt=0;
        g[mid]=-0x3f3f3f3f3f3f3f;
        for(ll i=x;i<=min(y,mid);i++)
        {
            if(tmp[i]+sum[mid-i]>g[mid])
            {
                g[mid]=tmp[i]+sum[mid-i];
                opt=i;
            }
        }
        solve(l,mid-1,x,opt);  solve(mid+1,r,opt,y);
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("apple.in","r",stdin);
        freopen("apple.out","w",stdout);
    #endif
        ll n,m=0,ans=0,base=20201205,i,j,k;
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>x[i];  m+=x[i];
        }
        for(i=1;i<=n;i++)
        {
            cin>>y[i];  v[x[i]].push_back(y[i]);
        }
        for(i=1;i<=5;i++)  
        {
            if(v[i].empty()==1)  continue;
            sort(v[i].begin(),v[i].end(),greater<ll>());
            for(j=1;j<=m/i;j++)  sum[j]=sum[j-1]+(j-1<v[i].size()?v[i][j-1]:0);// 因状态设计中表示的是 <=j 的最大价值,所以后面的也要处理(其实是分治的写法问题)
            for(j=0;j<=i-1;j++)
            {
                for(k=0;i*k+j<=m;k++)  tmp[k]=f[i*k+j];
                k--;  solve(0,k,0,k);
                for(k=0;i*k+j<=m;k++)  f[i*k+j]=g[k];
            }
        }
        for(i=1;i<=m+1;i++)  f[i-1]%=p;
        for(i=1;i<=m+1;i++,base=base*20201205%p)  ans=(ans+base*f[i-1]%p)%p;
        printf("%lld\n",ans);
        return 0;
    }
    

总结

  • 想了一整场 T1 怎么折半搜索。
  • T2n=3 之前多校模拟赛出过,遂 miaomiao 换题了。

后记

  • 题面中含有较多错别字。
posted @   hzoi_Shadow  阅读(81)  评论(7编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
历史上的今天:
2024-02-15 2024寒假年后集训日记
扩大
缩小
点击右上角即可分享
微信分享提示