2023牛客暑期多校训练营6

Tree 重构树 DP

Distance 组合数学,推式子,拆贡献

idol!! 数学题

Sequence 前缀和,结论

Gcd 分类讨论,细节

 2023牛客暑期多校训练营6_第1张图片

对边权进行排序,每次从小到大加入该边的左右集合。dp[i][j]代表 一个集合i个点里面,选了j个白点的最大收益。又因为当前边权一定是最大值,故左右集合内部贡献我们已经算出,只需要再在合并的时候,算上这条边新来的贡献即可。直接进行dp的话是一个n^3的,进行一个启发式合并,可将一个n缩短为log

#include 
using namespace std;
typedef long long int ll;
ll dp[3030][3030],f[3030],sizeson[3030];
ll temp[3030];
ll inf=1e18;
int getf(int x)
{
    if(x==f[x])
        return f[x];
    else
    {
        f[x]=getf(f[x]);
        return f[x];
    }
}
struct node
{
    int b,e;
    ll w;
};
struct node s[3030];
int col[3030];
ll cost[3030];
bool cmp(struct node x,struct node y)
{
    return x.w>n;
    for(int i=1; i<=n; i++)
    {
        f[i]=i;
        sizeson[i]=1;
    }
    for(int i=1; i<=n; i++)
    {
        cin>>col[i];
    }
    for(int i=1; i<=n; i++)
    {
        cin>>cost[i];
    }
    for(int i=1; i>s[i].b>>s[i].e>>s[i].w;
    }
    sort(s+1,s+n,cmp);
    for(int i=1; i<=n; i++)
    {
        if(col[i]==0)
        {
            dp[i][1]=0;
            dp[i][0]=-cost[i];
        }
        else
        {
            dp[i][1]=-cost[i];
            dp[i][0]=0;
        }
    }
    int root=0;
    for(int i=1; i=0; j--)
        {
            for(int rr=0; rr<=min(j,sizer); rr++)
            {
                ll LL=j-rr;
                ll leftbai=LL;
                ll lefthei=sizel-LL;
                ll righbai=rr;
                ll righhei=sizer-rr;
                if(LL<=sizel)
                    temp[j]=max(temp[j],dp[l][LL]+dp[r][rr]+(leftbai*righhei+lefthei*righbai)*s[i].w );
            }
        }

        sizeson[l]+=sizeson[r];
        f[r]=l;
        root=l;
        for(int j=0; j<=sizer+sizel; j++)
        {
            dp[l][j]=temp[j];
        }
    }

    root=getf(n);
    ll ans=-1e18;
    for(int i=0; i<=sizeson[root]; i++)
    {
        ans=max(ans,dp[root][i]);
    }
    cout<

 

 2023牛客暑期多校训练营6_第2张图片

 2023牛客暑期多校训练营6_第3张图片

 

考虑算贡献,a[i]和b[j]进行匹配时,贡献为其差的绝对值*合法集合数。枚举ij共同排名k,u之前选k个,u1也选k个,再枚举v,v1之后选几个。这样是一个n^3的,但是我们对u,u1,共同选k这一函数打表发现,这是一个完美的可以递推的函数。故找到规律后直接递推预处理,省去一维。

#include 
using namespace std;
typedef long long ll;
const int N = 4e3 + 7;
ll c[N][N];
ll a[N], b[N];
ll mp[N][N];
const ll mod = 998244353;
int main()
{
    for (int i = 0; i < N; i++)
    {
        c[0][i] = c[i][0] = 1;
    }
    for (int i = 1; i < N; i++)
    {
        for (int j = 1; j < N; j++)
        {
            c[i][j] = (c[i - 1][j] + c[i][j - 1]) % mod;
        }
    }
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
    }
    for (int i = 1; i <= n; i++)
    {
        scanf("%lld", &b[i]);
    }
    ll res = 0;
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n + 1);
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            if (a[i] == b[j])
            {
                continue;
            }
            // res += (((abs(a[i] - b[j]) * get(i - 1, j - 1)) % mod) * get(n - i, n - j)) % mod;
            int x = i - 1, y = j - 1, u = n - i, v = n - j;
            res += (((abs(a[i] - b[j]) * c[i - 1][j - 1] % mod) * c[n - i][n - j] % mod)) % mod;
            res %= mod;
        }
    }
    printf("%lld\n", res);
}

 2023牛客暑期多校训练营6_第4张图片

找规律,推式子,开int128数学题。 

 

 2023牛客暑期多校训练营6_第5张图片

做一个前缀和,对于前缀和的奇偶性再做前缀和。当分成k段每一段都是2的倍数时,首先[L,R]的前缀和必须也是2的倍数,即R和L-1的前缀和奇偶性相同。从R开始,一旦有一个跟其前缀和奇偶性相同的L,就分一段,直到L-1,故只需要看L-1到R-1有多少和R奇偶性相同的前缀和,要求有k-1个就行。 

#include 
using namespace std;
typedef long long ll;
const int N = 1e5 + 7;
ll c[N], q[N];
ll v[N][3];
int main()
{
    int t;
    scanf("%d", &t);
    while (t--)
    {
        int n, qq;
        scanf("%d%d", &n, &qq);
        for (int i = 1; i <= n; i++)
        {
            scanf("%lld", &q[i]);
            c[i] = c[i - 1] + q[i];
            v[i][c[i] % 2] = v[i - 1][c[i] % 2] + 1;
            v[i][!(c[i] % 2)] = v[i - 1][!(c[i] % 2)];
        }
        while (qq--)
        {
            int l, r, k;
            scanf("%d%d%d", &l, &r, &k);
            if ((c[r] % 2) != (c[l - 1] % 2))
            {
                puts("NO");
            }
            else
            {
                int op = c[r] % 2;
                int cnt = v[r - 1][op] - v[l - 1][op];
                if (cnt < k - 1)
                {
                    puts("NO");
                }
                else
                {
                    puts("YES");
                }
            }
        }
    }
}

2023牛客暑期多校训练营6_第6张图片 

分类讨论即可。 

 

 

你可能感兴趣的:(多校真题,区域赛,ICPC,算法)