首页 > 其他分享 >CSP 模拟 45

CSP 模拟 45

时间:2024-10-13 10:46:31浏览次数:1  
标签:子树 重心 int max 45 ch CSP 模拟 size

A 好数(number)

开桶记录。

B SOS字符串(sos)

\(f_{i,j,k,n}\) 表示到 \(i\),结尾两个字母是 \(j,k\),已经有了 \(0/1/2\) 个 SOS,字母有 \(4\) 类,分别为 O,没用过的 S,无用字母 X,用过的 S,的方案数,转移暴力。

C 集训营的气球(balloon)

首先有暴力背包,然后每次修改看成删除一个,添加一个,就成退背包的板子了。退背包从小到大退,保证了正确性。

D 连通子树与树的重心(tree)

题目中的子树含义是连通块,所以下面也是。
两种情况:第一种,两个重心,两个重心一定在一起,且他们子树的最大值恰好为 \(\frac{n}{2}\),整个子树大小相同,否则重心不能移动,只有一个。
对于这种情况只需要知道重心所在连通块大小的方案数就好了,设 \(f_{i,j}\) 表示以 \(i\) 为根,子树大小为 \(j\) 的方案数,树上背包转移,然后答案就是 \(\sum_{i=1}^{\frac{n}{2}}f_{rt1,i}f_{rt2,i}\),时间复杂度 \(\mathcal{O}(n^2)\)。
第二种情况,只有一个重心,设 \(g_{i,j}\) 表示以这个重心为根,联通块大小为 \(i\),且最大子树大小为 \(j\) 的方案数。答案就是 \(\sum_{i=1}^{n}\sum_{j=0}^{\frac{n}{2}-1}g_{i,j}\),如果等于的话就会有两个重心。借助 \(f\),可以再次背包出 \(g\),时间复杂度 \(\mathcal{O}(n^3)\)。
发现合法情况有很多,而不合法情况很少,因为只会有一个子树大小大于等于 \(\frac{size}{2}\),所以统计所有不合法的情况,最后减去即可。还是借助 \(f\),枚举重心的儿子作为不合法的情况,如果直接暴力重新背包时间复杂度还是 \(\mathcal{O}(n^3)\) 的,所以退背包求出不用每个儿子的方案,然后统计逐个统计即可。

#include<bits/stdc++.h>
#define pii std::pair<int,int>
#define eb emplace_back
typedef long long ll;
typedef unsigned long long ull;
std::mt19937 myrand(std::chrono::high_resolution_clock::now().time_since_epoch().count());
inline int R(int n){return myrand()%n+1;}
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=5e3+10,mod=10007;
int n,size[N],RT[2],num,d[N][N],f[N][N],ans;
std::vector<int> e[N];
inline void findrt(int x,int fa){
    size[x]=1;int max=0;
    for(int v:e[x]){
        if(v==fa)continue;
        findrt(v,x);size[x]+=size[v];max=std::max(max,size[v]);
    }max=std::max(max,n-size[x]);
    if(max<=n/2)RT[num++]=x;
}
inline void dfs(int x,int fa){
    d[x][1]=1;size[x]=1;
    for(int v:e[x]){
        if(v==fa)continue;
        dfs(v,x);
        for(int i=size[x];i;--i)for(int j=size[v];j;--j)d[x][i+j]=(d[x][i+j]+d[x][i]*d[v][j])%mod;
        size[x]+=size[v];
    }
}
inline void sub1(){
    dfs(RT[0],RT[1]);dfs(RT[1],RT[0]);
    for(int i=1;i<=n/2;++i)ans=(ans+d[RT[0]][i]*d[RT[1]][i])%mod;
}
inline void sub2(){
    dfs(RT[0],0);
    memset(f,0,sizeof(f));
    for(int v:e[RT[0]]){
		for(int i=1;i<=n;++i){
			f[v][i]=d[RT[0]][i];
			for(int j=1;j<=std::min(i,size[v]);++j)f[v][i]=(f[v][i]-f[v][i-j]*d[v][j])%mod;
		}
    }
	for(int i=1;i<=n;++i){
		ans=(ans+d[RT[0]][i])%mod;
		for(int v:e[RT[0]]){
			for(int j=(i+1)/2;j<=std::min(i,size[v]);++j)
				ans=(ans-d[v][j]*f[v][i-j])%mod;
		}
	}
	ans=(ans%mod+mod)%mod;
}
signed main(){
    // freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);
    // freopen("in.in","r",stdin);freopen("out.out","w",stdout);
    std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
    ans=0,num=0;
    n=read();for(int i=1;i<n;++i){int u=read(),v=read();e[u].eb(v);e[v].eb(u);}
    findrt(1,0);
    if(num==2)sub1();
    else sub2();
    std::cout<<ans<<'\n';
}

标签:子树,重心,int,max,45,ch,CSP,模拟,size
From: https://www.cnblogs.com/Ishar-zdl/p/18461951

相关文章

  • 『模拟赛』多校A层冲刺NOIP2024模拟赛06
    Rank比较还行A.小Z的手套(gloves)签。最大值最小,一眼二分答案。双指针check一下就完了,复杂度\(\mathcal{O(n\logn)}\)。点击查看代码#include<bits/stdc++.h>#definefo(x,y,z)for(registerint(x)=(y);(x)<=(z);(x)++)#definefu(x,y,z)for(regis......
  • CSP 模拟 46
    A二分答案,每个数去找范围内最左边的。B相同的数不会交换,所以设\(f_{i,j,k,u}\)为到\(i\),有了\(j\)个0,\(k\)个1,当前位置是\(u\)的最小代价,转移是暴力的,如果一个数要去前面,那么最优的方案一定不会把他往后面换,所以两次移动只有一次贡献,最终的答案要除以\(2\)。C首先......
  • 「模拟赛」多校 A 层联训 5
    A.好数(number)很签,打完之后“不是这题我能做一个小时??”对于每个数,都把它与前面的所有数的加和求一遍存进桶里,再遇到一个新数\(a_i\)时,枚举前面的所有\(a_j,j\in[1,i-1]\),找桶里是否存在一个数\(x\)使得\(x=a_i-a_j\)即可。因为这些数中有负数,所以我们可能会想到用map作......
  • 多校A层冲刺NOIP2024模拟赛06
    A.小Z的手套(gloves)明现的二分,我们先排序,假定\(a\)数组个数少,我们就对每一个\(a_i\)找一个\(b_i\)使其差不超过二分的值,然后贪心来讲,肯定找相差最大的那组但差不超过二分值的那个数最优,且先找比他小的那组(因为排过序了),然后套个\(multiset\)就过了,虽然\(n{log_n}^2\)......
  • [赛记] 多校A层冲刺NOIP2024模拟赛06
    小Z的手套(gloves)100pts最大值最小,考虑二分答案;首先排序,然后每次找出数量较少的那个数组中的每个数$x$在另一个数组中有没有值在范围$[x-mid,x+mid]$的(其中$mid$为二分的答案),其实只需找$x-mid$就行,最后判断一下所有数是否合法即可;因为已经升序排序,所以......
  • 多校A层冲刺NOIP2024模拟赛06
    多校A层冲刺NOIP2024模拟赛06\(T1\)A.小Z的手套(gloves)\(100pts/100pts\)容易发现将选出的左右手套各升序排序后,同一个位置上的两只手套的尺码差距一定在答案的候选集合里,画个数轴分讨一下就证完了。部分分\(20\%\):因为\(n=m\)所以不用管谁选谁不选的问题,故\(......
  • 多校 A 层冲刺 NOIP2024 模拟赛 06
    多校A层冲刺NOIP2024模拟赛06T小Z的手套(gloves)签到题答案显然具有单调性,排序后二分答案即可。T小Z的字符串(string)签到题注意到\(n\)较小,可以使用\(O(n^3)\)的算法,直接上大\(DP\)。设计状态\(f_{i,j,k,0/1/2}\)表示从左往右填到\(i\)位,已经填了\(j\)个\(0......
  • [赛记] 多校A层冲刺NOIP2024模拟赛05
    这场数数好数(number)100pts找三个数的和,而且允许$\Theta(n^2)$,那么我们可以维护出两个数的和,然后每次顺序遍历找这个数减去前面的某个数在任意两个数的和中有没有出现过,这个也是$\Theta(n^2)$的;所以时间复杂度:$\Theta(n^2)$,如果带$\log$会过不去,要用桶维护;点击......
  • Hoverfly 任意文件读取漏洞(CVE-2024-45388)
    漏洞简介Hoverfly是一个为开发人员和测试人员提供的轻量级服务虚拟化/API模拟/API模拟工具。其 /api/v2/simulation​的POST处理程序允许用户从用户指定的文件内容中创建新的模拟视图。然而,这一功能可能被攻击者利用来读取Hoverfly服务器上的任意文件。尽管代码禁止指定绝......
  • 代码随想录Day24 | LeetCode 122. 买卖股票的最佳时机 II、LeetCode 55. 跳跃游戏、Le
    LeetCode122.买卖股票的最佳时机IIclassSolution:defmaxProfit(self,prices:List[int])->int:res=0foriinrange(1,len(prices)):res+=max(0,prices[i]-prices[i-1])returnresLeetCode55.跳跃游戏class......