首页 > 其他分享 >DTOJ-2023-01-02-测试-题解

DTOJ-2023-01-02-测试-题解

时间:2023-01-14 21:36:57浏览次数:41  
标签:02 01 return int 题解 ll cdot2 solve omega

(2023 省选模拟 Round #4)

之前感冒了一阵子,错过了两场省选模拟,不过我不打算补(乐

成绩:0+42+0

(就是说 T1 写挂了)

A

题目链接

题目大意

小 \(\omega\) 最近学习了分治 \(\text{FFT}\),她想计算一类特殊的分治 \(\text{FFT}\) 的最小代价。分治的过程大致如下:

solve(l, r):
    if r - l == 1:
        process(l)
        return
    在开区间 (l, r) 中选取一个整数 mid
    solve(l, mid)
    fft(r - l)
    solve(mid, r)
    return

其中 process 函数执行时代价为 \(1\)。只有函数执行时计入代价。

其中 fft(n) 函数的代价计算方式如下:

  • 设 \(p\) 为最小的满足 \(2^p\geq n\) 的整数,则代价为 \(p\cdot 2^p\)。

小 \(\omega\) 希望知道在合适地选取 mid 的值的情况下调用 solve(0, n)最小代价(对 \(998244353\) 取模)。

小 \(\omega\) 在此基础上还要对 \(n\) 进行修改,具体方法是对 \(n\) 加上或减去 \(2^b\),你需要在每一次修改后输出你的答案。

\(n\) 特别大,输入的时候输入 \(k\) 段连续 \(1\) 的左右端点。对于所有数据,保证 \(0\le k,m\leq 1.5\times 10^5\),\(0\le b_i, l_i, r_i\leq 10^9\),保证 \(n\) 时刻为正。

题解

首先 dp 是容易的

注意到 solve(l,r) 的代价只与 \(r-l\) 有关

我们记 \(f_i\) 表示 solve(0,i) 的代价

那么根据题面里的代码,很容易给出状态转移方程

\[f_i=\min_{0<j<i} \{ f_j+f_{i-j}+p\cdot2^p \} \]

其中 \(j\) 就是代码中选取的 \(mid\) ,\(p=\lceil log_2{i}\rceil\)

这么直接做 \(O(n^2)\)

我们写个暴力程序找找规律,会发现每次转移的位置 \(j=2^{p-1}\)

这样我们就可以推式子了

\[\begin{gather*} f_{2^p}=2f_{2^{p-1}}+p\cdot2^p\\ g_p=2g_{p-1}+p\cdot2^p\\ g_p=2(2(\cdots(g_0\cdots+(p-1)\cdot2^{p-1})+p\cdot2^p\\ g_p=2^p+(1+\dots+p)\cdot2^p\\ g_p=2^p+\frac{p(p+1)}{2}2^{p} \end{gather*} \]

\[\begin{align*} f_n&=f_{2^t}+f_{n-2^t}+(t+1)\cdot2^{t+1} (n\ne2^p)\\ &=(1+2(t+1)+\frac{t(t+1)}{2})2^t+f_{n-2^t}\\ &=\sum_{(n>>t)\&1=1}\left((1+2(t+1)+\frac{t(t+1)}{2})2^t\right)-(l_1+1)2^{l_1+1}\\ &=\sum_{(n>>t)\&1=1}\left((t^2+5t+6)2^{t-1}\right)-(l_1+1)2^{l_1+1}\\ \end{align*} \]

现在我们只需要求连续一段区间的和

使用错项相减或待定系数法等技巧可以求出

\[\sum_{t=L}^{R}\left((t^2+5t+6)2^{t-1}\right)=2^R(R^2+3R+4)-2^{L-1}((L-1)^2+2(L-1)+4) \]

使用 set 可以维护连续的全 \(1\) 区间,细节有点多不过还好

时间复杂度 \(O((k+m)\log P)\)

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 1.5e5+5, P = 998244353;
int k,m;
int qpow(int a, int b) { int res=1; for(; b; b>>=1,a=(ll)a*a%P) if(b&1) res=(ll)a*res%P; return res; }
int work(int L, int R) { auto f=[&](const int &x) { if(x==-1) return 1ll; return (ll)qpow(2,x)*((ll)x*(x+3)%P+4)%P; }; return (f(R)-f(L-1)+P)%P; }
struct Misaka { int l,r; friend bool operator< (const Misaka &a, const Misaka &b) { return a.l<b.l; } };
set<Misaka> st;
int main()
{
	scanf("%d%d",&k,&m);
	int ans=0;
	for(int i=1,l,r; i<=k; i++) 
	{
		scanf("%d%d",&l,&r); st.insert({l,r});
//		for(int j=l; j<=r; j++) (ans+=(ll)qpow(2,j-1)*(j+2)%P*(j+3)%P)%=P;
		(ans+=work(l,r))%=P;
	}
//	printf("%d\n",ans);
	for(int i=1,op,b; i<=m; i++)
	{
		scanf("%d%d",&op,&b);
//		printf("b=%d\n",b);
		if(op==0)
		{
			auto it=st.lower_bound((Misaka){b+1,b+1});
			if(it==st.begin() or (*prev(it)).r<b)
			{
				(ans+=work(b,b))%=P; st.insert({b,b});
			}
			else
			{
//				puts("!!2!!");
				auto t=*prev(it); Misaka t2={t.r+1,t.r+1}; 
				ans=(ans-work(b,t.r)+P)%P; (ans+=work(t.r+1,t.r+1))%=P; t.r=b-1;
				st.erase(prev(it)); if(t.l<=t.r) st.insert(t); st.insert(t2);
			}
		}
		else
		{
			auto it=st.lower_bound((Misaka){b+1,b+1});
			if(it==st.begin() or (*prev(it)).r<b)
			{
				auto t=*it; (ans+=work(b,t.l-1))%=P; ans=(ans-work(t.l,t.l)+P)%P;
//				printf("[%d,%d]\n",t.l,t.r);
				st.erase(it); st.insert({b,t.l-1}); t.l++; 
//				puts("!!");
				if(t.l<=t.r) st.insert(t);
			}
			else
			{
				auto t=*prev(it); ans=(ans-work(b,b)+P)%P; st.erase(prev(it));
				if(t.l<=b-1) st.insert({t.l,b-1});
				if(b+1<=t.r) st.insert({b+1,t.r});
			}
		}
		auto it=st.lower_bound((Misaka){b,b});
		if(it!=st.end())
		{
			auto u=*it;
			if(it!=st.begin() and u.l==(*prev(it)).r+1)
			{
				u.l=(*prev(it)).l;
				st.erase(prev(it));
			}
			if(it!=prev(st.end()) and u.r==(*next(it)).l-1)
			{
				u.r=(*next(it)).r;
				st.erase(next(it));
			}
			st.erase(it); st.insert(u);
		}	
		int t=(*st.begin()).l; int lv=(ll)(t+1)*qpow(2,t+1)%P;
		printf("%d\n",(ans-lv+P)%P);
	}
	return 0;
}

B

题目链接

题目大意

小 \(\omega\) 是一个喜欢随机的人,所以他又开始随机了。

他有一个长度为 \(n\) 的排列,他想将它排序。于是他写了一个冒泡排序。其中冒泡一次的伪代码如下:

for j = 2 to n do
	if a[j] < a[j - 1] then
		swap(a[j], a[j - 1])

这当然是对的了,于是小 \(\omega\) 愉快的使用了它。

但是,他发现出现了问题!第 \(2\) 行的比较可能会返回错误的结果!

具体的来说,它有 \(233 / 12345679\) 的概率会返回错误结果,否则它将会返回正确的结果。

小 \(\omega\) 发现这样排序就会错误,于是,他只好做了 \(m\) 遍冒泡,希望提高正确率。

现在,钱菜鸡想知道冒泡 \(m\) 次后第 \(i\) 个数的期望大小,你能帮帮他吗。

\(n\leq 15, m \leq 500\)

题解

暴力很简单

每个排列可以看做一个点,每做一次交换,有两条出边,于是可以在上面 dp

\(f_{i,j}\) 表示交换 \(j\) 次后,是排列 \(i\) 的概率

转移是容易的

时间复杂度 \(O(n!mn)\) ,\(42\) 分

正解只需要做一个优化

冒泡 \(m\) 次后 \(E(a_i)=P(a_i\geq1)+P(a_i\geq2)+\dots+P(a_i\geq n)\)

然后对于 \(P(a_i\geq k)\),可以把 \(\geq k\) 变成 \(1\) 反之 \(0\),然后 \(dp\)

因为状态数是 \(\binom{n}{k}\) ,所以时间复杂度是 \(\sum \binom{n}{k}=2^n\),可以通过

事实上这些状态互不重复,可以一起 dp

代码

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 20, M = 33000, P = 12345678;
int a[N],pos[N],n,m,f[M][2],ans[N];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++) scanf("%d",&a[i]),pos[a[i]]=i;
	for(int i=n,cur=0; i; i--) { cur|=(1<<(pos[i]-1)); f[cur][0]=1; }
	int t=0;
	for(int i=1; i<=m; i++) for(int j=1; j<n; j++)
	{
		int swp=(1<<(j-1))|(1<<j);
		for(int u=0; u<(1<<n); u++) if(f[u][t])
		{
			int t1=(u>>(j-1))&1; int t2=(u>>j)&1;
			int v=(t1==t2)?u:(u^swp); int p1=(t1<t2)?233:(1-233+P);
			(f[u][t^1]+=(ll)(1-p1+P)*f[u][t]%P)%=P;
			(f[v][t^1]+=(ll)p1*f[u][t]%P)%=P;
		}
		for(int u=0; u<(1<<n); u++) f[u][t]=0; t^=1;
	}
	for(int u=0; u<(1<<n); u++) for(int i=0; i<n; i++) if((u>>i)&1) (ans[i+1]+=f[u][t])%=P;
	for(int i=1; i<=n; i++) printf("%d ",ans[i]);
	return 0;
}

标签:02,01,return,int,题解,ll,cdot2,solve,omega
From: https://www.cnblogs.com/copper-carbonate/p/17052568.html

相关文章

  • 2023/1/14 20221321杨渝学习打卡
    python学习学习链接:https://www.bilibili.com/video/BV14r4y1k7F9/?spm_id_from=333.999.0.0&vd_source=a989a1afa6cb8b6527dd9bf059d71439元组字典元组元组,英文为t......
  • 230114_50_SpringBoot入门
    主启动类详解packagecom.bill;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@Spr......
  • VS2022/CLion配置环境变量(再也不用复制dll/配置系统环境变量啦)
    事情的起因是我想在VS里使用OpenCV和LibTorch外部库,在按照网上的步骤设置好包含目录、库目录等后(参考百度即可)​一般还需要我们在系统环境变量path里配置一些dll的目录........
  • 【题解】P4565 [CTSC2018]暴力写挂
    能写点分为什么要写这种玄学东西。思路边分树合并。首先考虑点分,发现只会T飞的做法。但是答案的形式有点意思,换一下写法:\(ans=\frac{1}{2}\max(\operatorname{dis......
  • 2022MoeCTF整理复现(NSS平台)
    一、[MoeCTF2022]小纸条1.jpg上的像是某种形式的猪圈密码,找一个对照表边猜边对照2.根据点和角的位置方向以及可能拼写成的单词,得到flagmoectf{ILOVEMYBIGBED}二、[M......
  • Media Encoder 2021 for Mac(ame 2021) v15.4.1中文直装版
    MediaEncoder2021中文版是一款优秀的视频音频编码器,能够将多种设备格式的音频或视频进行导出,提供了丰富的硬件设备编码格式设置以及专业设计的预设设置,方便用户导出与特定......
  • 01-初识C#
    一、C#简史在.NETFramework开发期间,其类库最初是使用一种被称为``SimpleManagedC(SMC/简单托管C)`的编译系统开发的。C#读作CSharp。最初它有个更酷的名字,叫做COOL。......
  • Codeforces 1630 E Making It Bipartite 题解 (Dilworth定理)
    题目链接首先可以想到把题目中的那张图G建出来,由于要求这张图是二分图,把它复制一遍(\(G\toG'\)),然后对于每个u,连一条无向边\(u-u'\),这样就变成了最大独立集问题。但是一......
  • Codeforces 1630 E Making It Bipartite 题解 (Dilworth定理)
    题目链接首先可以想到把题目中的那张图G建出来,由于要求这张图是二分图,把它复制一遍(\(G\toG'\)),然后对于每个u,连一条无向边\(u-u'\),这样就变成了最大独立集问题。但是一......
  • x210-2023-01-13
    1、在使用gcchello.c-ohello的这种默认情况下,实际上是动态链接,想要静态链接,使用gcc-statichello.c-ohello。2、图1立即数缺#;图2由于立即数不符合整除4;   ......