首页 > 其他分享 >[Tricks-00004]CF1954F(自己胡的 trick,被 Burnside 完爆)

[Tricks-00004]CF1954F(自己胡的 trick,被 Burnside 完爆)

时间:2024-11-17 15:45:51浏览次数:1  
标签:完爆 CF1954F int dfrac Tricks 3005 权值 sum mod

介绍下自己的离奇思路:

先读清楚题意!要求是旋转等价,即两个以 \(c\) 个 \(1\) 开头,总 \(1\) 个数不超过 \(k+c\) 的字符串算一种。

那怎么刻画"只算一种"这个条件呢?一个想法可以是,对每个字符串赋一个权值,一种字符串的权值即旋转出来的每个合法的,把它们加起来应该是 \(1\),再全部加出来。

一个直接的赋权方式是,对一个最小循环节是 \(d(d|n)\) 的字符串,它的权值为 \(\dfrac{1}{\sum\limits_{i=1}^{d}ok_i}\),其中 \(ok_i\) 代表字符串是否可以以位置 \(i\) 开头。

然后做法就是枚举 \(d\),求出容斥系数,因为要考虑所有大小为 \(d\) 的 \(01\) 串,所以要 dp 三个量:长度,\(1\) 个数,以及合法开头点数。这样复杂度肯定没救了。

这是同学你可能会说:没必要让每个"合法点"都合法作为开头啊?我对于一个 \(len\geq c\) 的 \(1\) 段,要求上必须以这个段的段头作为开头才可以,这不就轻松了吗?

很好!这样就改为了段数分之一,不过还是要 dp 这个段数有点烦,怎么办呢?

其实这时候你可以发现,我们没有必要非去设它的所有合法轮换的权值都相等啊!只需要加起来是 \(1\) 就可以。于是容易想到,停时定理那个设权值的方式,即 \(\dfrac{a_i}{\sum a_k}\),换在这题也就是,目前一个段到下一个合法段的距离,除掉总长,也就是 \(d\)。而目前段就是 \(1\sim c\) 开头那个尽量延伸,且要求 \(s_d=0\),即必须要是一个段头。

这下我们就不需要考虑这个字符串整体了,只需要得到一个最前的合法段,钦定即可!

其实可以两种情况分开讨论:

第一种情况的权值是 \(\dfrac{x-1}{d}\),其中 \(x\) 表示后面那个合法段的开头位置。第二种的权值就是 \(\dfrac{d}{d}=1\)。

显然情况一更难,我们只考虑这个咋求。不难发现,枚举 \(x\) 的位置,和 \(x\) 前面 \(0\) 的个数,就可以通过一些预处理做到除了预处理之外单次 \(O(d^2)\) 的复杂度。

那么预处理是什么呢?也不难,就是 \(f_{i,j}\) 表示长度为 \(i\),以 \(0\) 结尾,不能出现连续 \(c\) 个 \(1\) 的字符串数,则有转移:

\[f_{i,j}=\sum\limits_{k=0}^{c-1}f_{i-k-1,j-1} \]

其实这个甚至只用 \(+1\) 优化都可以做,完全不需要前缀和优化。不过其它一些预处理可能要前缀和优化,不过都很简单。这里是 \(O(n^2)\) 的。

最后一个小问题是我们枚举的是 \(d\),也就是钦定了有大小为 \(d\) 的循环节。注意,最小循环节一定整除其它的,所以容斥系数可以直接这么理解:

\[f_d=\dfrac{n}{d}-\sum\limits_{d|g|n\land g\neq d}f_g \]

然后乘乘加加就可以了。复杂度是 \(O(n^2+\sum\limits_{d|n}d^2)=O(\sum\limits_{i\geq 1}\dfrac{n}{i}^2)=O(n^2)\)。

这是我的做法,代码如下,很短:

#include<bits/stdc++.h>
#define mod 1000000007
using namespace std;
int powdv(int x,int y=mod-2){
	int ans=1;
	while(y){
		if(y&1)ans=1ll*ans*x%mod;
		y>>=1,x=1ll*x*x%mod;
	}
	return ans;
}
int ff[3005],hh[3005];
int f[3005][3005],h[3005][3005];
int main(){
	int n,c,k;
	scanf("%d%d%d",&n,&c,&k);
	for(int d=n;d>=1;--d)if(n%d==0){
		ff[d]=powdv(d);
		for(int g=2*d;g<=n;g+=d)if(n%g==0){
			ff[d]=(ff[d]-ff[g]+mod)%mod;
		}
	}
	f[1][1]=1;
	for(int i=2;i<=n;++i)for(int j=2;j<=i;++j){
		f[i][j]=(f[i-1][j]+f[i-1][j-1])%mod;
		if(i>c+1)f[i][j]=(f[i][j]-f[i-c-1][j-1]+mod)%mod;
	}
	h[0][0]=1;
	for(int i=1;i<=n;++i)for(int j=0;j<=i;++j){
		h[i][j]=(h[i-1][j]+(j?h[i-1][j-1]:0))%mod;
	}
	for(int i=1;i<=n;++i)for(int j=i;j>=1;--j){
		h[i][j-1]=(h[i][j-1]+h[i][j])%mod;
	}
	int ans=0;
	for(int d=c+1;d<=n;++d)if(ff[d]){
		int mx=(k+c)/(n/d),gs=max(0,d-mx),he=0;
		for(int i=1;i<=d-c;++i)for(int j=gs;j<=i;++j){
			he=(he+1ll*d*f[i][j])%mod;
		}
		for(int i=1;i<=d;++i)hh[i]=0;
		for(int i=c+2;i<=d-c;++i){
			int ht=0;
			for(int j=1;j<=i;++j){
				hh[j]=(hh[j]+f[i-c-1][j])%mod;
				ht=(ht+1ll*hh[j]*h[d-c-i][max(0,gs-1-j)])%mod;
			}
			he=(he+1ll*(i-1)*ht)%mod;
		}
		ans=(ans+1ll*ff[d]*he)%mod;
	}
	if(k==n-c)ans=(ans+1)%mod;
	printf("%d\n",ans);
	return 0;
}

另外说说 Burnside 的做法,也是积累了一个套路:

------------------分割线--------------------

看了眼题解,怎么这么简单???我最开始的时候想用 Burnside,可是发现不完备,遂放弃。实际你仔细想想,发现我只要不要求必须以 \(c\) 个 \(1\) 开头就好了啊!!!!!只用这样一件事情:存在相邻 \(c\) 个字符全为 \(1\),之后就还是枚举循环节去 Burnside 就好了。思维难度少了 \(114514\) 倍,唉唉唉。

标签:完爆,CF1954F,int,dfrac,Tricks,3005,权值,sum,mod
From: https://www.cnblogs.com/maihe/p/18550504

相关文章

  • [Tricks-00003]CF1989F 套路叠加,高级分治
    先说一个简单问题:给定一个\(n\timesm\)的黑白网格图,每次可以将一行或者一列染成同一种色,判断是否能到达?经典做法:倒过来考虑,每次将颜色全相同或为*的一行全染成*,判断是否可以将这张图染成全*。经典网格图转二分图,如果\(s_{i,j}='W'\)则将\(i\)向\(j'\)连一条有向边,否......
  • [CEOI2023] Tricks of the Trade 题解
    Description有\(n\)个机器人排成一排,第\(i\)个机器人的购买价是\(a_i\)欧元,卖出价是\(b_i\)欧元。给定\(1\lek\len\),你需要购买一段长度至少为\(k\)的区间中所有的机器人,然后选择其中的恰好\(k\)个机器人来卖出。你需要求出:你能够得到的最大收益;在收益最大化......
  • 九析带你轻松完爆AI大模型(九)---RAG介绍
    申明:九析唯一授权【超级网红系列课程——AI大模全栈型架构师】系列课程邀约    诚挚邀请您关注公众号,通过公众号加入群聊和我们一起完爆世界,有任何问题在群里我们一起探讨......期待与您的见面!​ 一、RAG简介    众所周知,我们在使用大语言模型做应用......
  • 九析带你轻松完爆AI大模型(四)---模型篇①
    申明:九析唯一授权【超级网红系列课程——AI大模型全栈架构师】系列课程一、模型篇大纲大语言模型基础大语言模型预训练大语言模型微调大语言模型强化对齐大语言模型评估大语言模型压缩大语言模型工程大语言模型安全多模态模型大模型经典论文Pytorch......
  • [Tricks-00002]CF2026F 操作建树&维护带删deque信息的经典套路
    这怎么是*2700???我大受震撼了好吧。简要题意:有一个初始长度是\(cnt=1\)的序列\(S\),序列每个位置都是若干个二元组\((p,t)\)组成的可重集,初始时\(S_1\)为空集。\(q\)组操作(为修改或询问),有如下四种操作:1x:把\(S_x\)复制到一个新加的点\(S_{++cnt}\)上。2xpt:将\((p......
  • C++刷题tricks整理
    是自己做题中整理的常用C++操作,此为存档。STL容器容器适配器,STL里面的vector/array/deque/set/map/unordered_set可以直接使用==比较是否相等:vector<int>a;deque<int>a;map<int,string>a;unordered_map<int,string>a;set<int>a;unordered_set<int>a;forward_lis......
  • tricks
    二分答案P2824排序有时候可以尝试二分最后的答案,把不好维护的东西变成\(0\)和\(1\)。操作分块P5443桥梁将操作分块维护,一般适用于可以很好维护静态询问但是需要支持修改的情况(?)。状态压缩去除后效性P2157学校食堂dp有后效性但影响范围很小可以考虑把后续决策压缩起......
  • Tricks(长期更新)
    会很杂,尽量分类,每个trick会配题。难以分类的难以分类可能只是自己太菜了。曼哈顿距离与切比雪夫距离的转化对于两点\((x_1,y_1),(x_2,y_2)\),曼哈顿距离为\(|x_1-x_2|+|y_1+y_2|\),切比雪夫距离为\(\max(|x_1-x_2|,|y_1-y_2|)\)。画图可以发现到原点的曼哈顿距离为\(1\)的点形......
  • 一些常用tricks,基础知识收录
    uoj转,YAML的ppt格式不想改了,将就看看吧|一些常用tricks,基础知识收录byzsjchildren:|题目链接:T1:CF504EMishaandLCPonTreeT2:LuoguP2617DynamicRankingsT3:LuoguP4197PeaksT4:LuoguP4690[Ynoi2016]镜中的昆虫T5:H1079.E.‘MinamiKotori......
  • Tricks
    感谢huangkx的trick转载。用可持久化线段树维护非递归线段树的树链信息可以高效地解决区间半群问题。线段树维护的序列长度要保持不变。关于\(d\)(约数个数函数):\(d(nm)=\sum_{x\midn}\sum_{y\midm}[\gcd(x,y)=1]\);由此可以推导出当\(m\)为......