首页 > 其他分享 >CodeForces - 1982E

CodeForces - 1982E

时间:2024-07-14 09:10:23浏览次数:8  
标签:1982E lmx int rmx CodeForces len merge state

分析

可以设状态 \(f_{l,r,k}\) 表示区间 \([l,r],bit(x\in[l,r])\le k\)的{前缀长度,后缀长度,总方案数}。
合并即找一个 \(mid\),类似最大子段和的合并。
如何找个 \(mid\) 是解题的关键,关于二进制分治题目,令 \(mid\) 为 highbit 或
lowbit 通常有很好的性质,本题 \(mid\) 为highbit。
设 \(mid=2^m-1\),其中 \(2^m\) 是 \(n-1\) 的 highbit,转移方程有:
\(f_{0,n-1,k}=merge(f_{0,2^m-1,k},merge(2^m,n-1,k))\)
观察后面状态,发现highbit都为 2^m,考虑去掉这一位 1,转移方程变成:
\(f_{0,n-1,k}=merge(f_{0,2^m-1,k},merge(0,n-1-2^m,k-1))\)
发现 \(l\) 恒等于 0,于是将区间改为长度,即 \(f_{i,k}\) 表示(从0开始)长度为 \(i,bit(x) \le k\) 的{前缀长度,后缀长度,总方案数}。
转移方程改为 \(f_{n,k}=merge(f_{2^m,k},f_{n-2^m,k-1}\),但此时时间复杂度依然是线性的。
发现转移前部分状态是固定,考虑预处理,设 \(g_{k,i}\) 为 \(bit(x)\le k\),长度为 \(2^i\) 的状态。
转移方程类比上式有:
\(g_{k,i}=merge(g_{k,i-1},g_{k-1,i-1})\)
于是,时间复杂度变为 \(O(klogn+logn)\),可以通过此题。

代码

int n,k;

int mul(int x,int y){
	int res=0;
	while(y){
		if(y&1) res=(res+x)%mod;
		x=(x+x)%mod;y>>=1;
	}
	return res;
}

struct state{
	int len,lmx,rmx,ans;
	friend state operator +(state a,state b){
		state c;
		c.lmx=a.lmx;
		if(a.lmx==a.len) c.lmx=max(c.lmx,a.len+b.lmx);
		c.rmx=b.rmx;
		if(b.rmx==b.len) c.rmx=max(c.rmx,b.len+a.rmx);
		c.ans=(a.ans+b.ans+mul(a.rmx,b.lmx))%mod;
		c.len=a.len+b.len;
		return c;
	}
}dp[K][K];

state solve(int n,int k){
	if(n==0) return {0,0,0,0};
	if(k==0) return {n,1,(n==1),1};
	int t;
	for(t=60;~t;t--) if(n>>t&1ll){break;}
	return dp[k][t]+solve(n-(1ll<<t),k-1);
}

void Main(){
	n=rd,k=rd;
	cout<<solve(n,k).ans<<endl;
}

signed main(){
	for(int i=0;i<=60;i++)
		dp[0][i]={1,1,(i==0),1};
	for(int k=1;k<=60;k++){
		dp[k][0]={1,1,1,1};
		for(int i=1;i<=60;i++){
			dp[k][i]=dp[k][i-1]+dp[k-1][i-1];
		}
	}
	int T=rd;
	while(T--) Main();
}

标签:1982E,lmx,int,rmx,CodeForces,len,merge,state
From: https://www.cnblogs.com/smilemask/p/18301090

相关文章

  • 题解:Codeforces CF1613C Poisoned Dagger
    标签:二分题意给定一个长度为\(n\)的序列\(a\),定义数\(k\),对于\(i>1\),如果\(a_i-a_{i-1}<k\),\(s\)加上\(a_i-a_{i-1}\),否则加上\(k\),求满足\(s\geqh\)的最小\(k\)。思路手玩样例,\(k\)越大龙死的越快,所以具有单调性,考虑二分答案。每次缩小范围时判断是否\(k\g......
  • CodeForces Round 957 (Div3)
    蒟蒻找了一些简单题做了而已,别太在意……比赛链接CodeForcesRound957(Div3)A.OnlyPluses题意三个正整数\(a,b,c\),有五次操作机会。每次操作:选取\(a,b,c\)中任意一个数,将这个数加上一。要求最大化\(a\timesb\timesc\)。思路很直接的贪心题。假设有三个正整......
  • Codeforces Round 957 (Div. 3) A-G 题解
    CodeforcesRound957(Div.3)A-G题解A.OnlyPluses枚举思路:枚举\(a\),\(b\),\(c\)增加的次数,维护最值即可。代码:#include<bits/stdc++.h>usingnamespacestd;#definefffirst#definesssecond#definepbpush_back#defineall(u)u.begin(),u.end()#......
  • CodeForces - 1984F
    分析考虑相邻两个字符带来的约束。若为"SS",则满足$|b_i-b_{i+1}|\lem$若为"PP",则满足\(|b_{i+1}-b_i|\lem\)若为"PS",则满足\(tot_a=b_i+b_{i+1}\)若为"SP",则满足\(tot_a+a_{i}+a_{i+1}=b_i+b_{i+1}\)发现可以枚举"PS"的位置来确定\(to......
  • Codeforces Round 957 (Div. 3)
    E-Novice'sMistake题意为寻找n*a-b=("n"+"n"+...){a个n的字符串-b的长度}即为"2"⋅20−18="22222222222222222222"−18=22=2⋅20−18使用暴力枚举每个n相加的长度和又因为n<=100a<=100000所有答案t的值必定小于1e6所以对每个a进行枚举对于每个答案t进行判断是否成立其......
  • CodeForces - 1987F1 & CodeForces - 1987F2
    分析首先显然有dp状态\(g_i\)表示前\(i\)个数,能进行最大的操作次数。转移有\(g_i=\max\limits_{j=1}^{i-1}(g_j+\frac{i-j}{2})[2|(i-j)]\)但这里显然缺少转移条件。经过基本观察,发现若\(i\)操作过,满足条件:\(a_i\equivi(mod\2)\)\(i\)左侧操作过\(\frac{i-......
  • Codeforces Round 957 (Div. 3)
    推荐个C++编程仓库模板https://github.com/yxc-s/programming-templateA.OnlyPluses总结:为什么优先增加最小的数,它们的乘积会是最优的呢?可以这么理解,假如只有两个数a和b,b>a,那么a+1,就增加一份b。如果b+1,只能增加1份a。因为b>a,所以增加小的数是最优的。voidsolve(){......
  • Codeforces Round #956 (Div. 2)题解
    A.ArrayDivisibility需要让满足$k\midj$的所有\(a_j\)的和整除k,只需要让每个\(a_j\)整除k就可以了,可以让\(a_j=j\)#include<bits/stdc++.h>usingnamespacestd;#defineintlonglong#defineendl'\n'typedefpair<int,int>pii;typedefunsignedlonglo......
  • CodeForces - 1986G1 & CodeForces - 1986G2
    经过基本观察,可得当点对\((i,j)\)合法时,有\(a_i|b_j,a_j|b_i\),其中\(a_i=i/gcd(p_i,i),b_i=p_i/gcd(p_i,i)\),证明显然。如何维护?考虑开\(mp_{x,y}\)表示\(x=a_i\),\(y|b_i\)的个数。对于点\(i\)点对个数即为\(\sum\limits_{d|b_i}mp_{d,a_i}\)时间复杂度为\(O(nlog......
  • CodeForces - 1984E
    题目大意每次在每个联通块中选一个点\(u\),删除这个点使得联通块分成若干个联通块,再从联通块中选点\(v\),在新树上连接\(u,v\),求新树叶节点的最大个数。分析易转化为求原树的最大独立集,设\(f_{u,0/1}\)为以1为根时不选/选\(u\)的最大独立集。显然有:\[dp_{u,0}=\sum\li......