ZJOI 2022 题目选做

题目描述

点此看题

解法

考虑这样的一个计数方法:对于一个点,我们考虑其在第一棵树上是叶子,第二棵树上是非叶子;或者在第一棵树上是非叶子,第二棵树上是叶子的状态。那么记录第一棵树前面的非叶节点个数,记录第二棵树后面的非叶节点个数,就可以方便地计算方案数。

但是这样做会出现一个明显的问题:我们的非叶节点可能并没有被连边,解决这个问题可能需要记录更多的状态。但是我们可以容斥没有被连边的非叶节点数量,每多一个这样的点就记上 \(-1\) 的容斥系数。

\(f[j][k]\) 表示考虑到当前点,第一棵树前面有 \(j\) 个非叶节点,第二棵树后面有 \(k\) 个非叶节点,状态中的非叶节点是不包含 \(1/n\) 的,所以计算方案数的时候还要把连向它们的边考虑到,转移:

  • \(i\) 在第一棵树上是叶子,第二棵树上是非叶子:\(f[j][k]\leftarrow (j+1)\cdot (k+1)\cdot f[j][k+1]\);如果在第二棵树上是没有被连边的非叶子:\(f[j][k]\leftarrow -(j+1)\cdot (k+1)\cdot f[j][k]\)
  • \(i\) 在第一棵树上是非叶子,第二棵树上是叶子:\(f[j][k]\leftarrow j\cdot (k+1)\cdot f[j-1][k]\);如果在第一棵树上是没有被连边的非叶子:\(f[j][k]\leftarrow -(j+1)\cdot (k+1)\cdot f[j][k]\)

时间复杂度 \(O(n^3)\)

总结

一开始我直接对不合法的状态容斥(都是叶子,都是非叶子),结果复杂度爆炸。

所以事实证明容斥不只有直接容斥这一种思考方向,本题的逻辑就是先给出一种会算重的计数方法,然后找出这种计数方法算重的原因,然后对这个算重的原因容斥就得到了复杂度很美妙的做法。

#include <cstdio>
const int M = 505;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,MOD,f[M][M],g[M][M];
signed main()
{
    n=read();MOD=read();
    for(int i=0;i<=n;i++) f[0][i]=i+1;
    puts("1");
    for(int i=2;i<n;i++)
    {
        for(int j=0;j<=i;j++)
            for(int k=0;k<=n-i;k++)
                g[j][k]=f[j][k],f[j][k]=0;
        for(int j=0;j<=i;j++)
            for(int k=0;k<=n-i;k++)
            {
                int r=0;
                r+=(j+1)*(k+1)*g[j][k+1];
                r-=(j+1)*(k+1)*g[j][k];
                if(j) r+=j*(k+1)*g[j-1][k];
                r-=(j+1)*(k+1)*g[j][k];
                f[j][k]=(r%MOD+MOD)%MOD;
            }
        int ans=0;
        for(int j=0;j<=i;j++)
            ans=(ans+(j+1)*f[j][0])%MOD;
        printf("%lld\n",ans);
    }
}

众数

题目描述

点此看题

解法

众数问题基本上不能 \(poly\ log\),所以我们着重考虑一些根号算法。

可以对不同颜色的出现次数根号分治,称出现次数 \(\geq \sqrt n\) 的为大颜色,否则为小颜色。

首先考虑大颜色对其他颜色的贡献,可以把大颜色打在原来的序列上,做完前缀和之后枚举其他颜色,按顺序扫描,记录前缀最小值就可以做到 \(O(n)\),这一部分总时间 \(O(n\sqrt n)\)

然后考虑小颜色对其他颜色的贡献,这时候要抓住关键性质:选取的区间众数应当 \(\leq \sqrt n\),那么我们外层枚举众数大小 \(x\),然后双指针就可以获得 \(p_r\) 表示右端点 \(r\) 对应最大左端点,使得众数为 \(x\),得到这个数组之后我们枚举颜色 \(y\),对于 \(y\) 的每一个点,我们双指针维护最大的左端点使得两点间区间众数为 \(x\),贡献就便于计算了,这一部分时间复杂度也是 \(O(n\sqrt n)\)

#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int M = 200005;
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int T,n,m,k,a[M],b[M],c[M],s[M],ans[M],p[M],mi[M];
vector<int> g[M];
void work()
{
    n=read();k=sqrt(n);
    for(int i=1;i<=n;i++)
        a[i]=b[i]=read(),c[i]=ans[i]=0,g[i].clear();
    sort(b+1,b+1+n);m=unique(b+1,b+1+n)-b-1;
    for(int i=1;i<=m;i++) g[i].push_back(0);
    for(int i=1;i<=n;i++)
    {
        c[a[i]=lower_bound(b+1,b+1+m,a[i])-b]++;
        g[a[i]].push_back(i);
    }
    for(int i=1;i<=m;i++) g[i].push_back(n+1);
    for(int x=1;x<=m;x++) if(c[x]>=k)
    {
        for(int i=1;i<=n;i++)
            s[i]=s[i-1]+(a[i]==x);
        s[n+1]=s[n];
        for(int y=1;y<=m;y++) if(x^y)
        {
            int mn=0;
            for(int i=1;i<g[y].size();i++)
            {
                int nw=s[g[y][i]]-i;
                ans[y]=max(ans[y],nw-mn+1);
                mn=min(mn,nw);
            }
        }
    }
    for(int x=k;x>=1;x--)
    {
        for(int i=1;i<=m;i++) s[i]=0;
        for(int r=1,l=1;r<=n;r++)
        {
            s[a[r]]++;
            while(s[a[r]]>=x) s[a[l]]--,l++;
            p[r]=l;
        }
        for(int y=1;y<=m;y++) if(ans[y]<x)
        {
            vector<int> &t=g[y];
            for(int i=1,j=0,k=0;i<t.size();i++)
            {
                if(p[k=t[i]-1]<2) continue;
                while(j<i && t[j+1]<p[k]-1) j++;
                if(j<i) ans[y]=max(ans[y],x-(i-j-1));
            }
        }
    }
    int mx=0;
    for(int i=1;i<=m;i++) mx=max(mx,ans[i]+c[i]);
    printf("%d\n",mx);
    for(int i=1;i<=m;i++)
        if(ans[i]+c[i]==mx) printf("%d\n",b[i]);
}
signed main()
{
    T=read();
    while(T--) work();
}
posted @ 2022-05-16 16:41  C202044zxy  阅读(149)  评论(0编辑  收藏  举报