首页 > 其他分享 >2022/11/07-13 训练小记

2022/11/07-13 训练小记

时间:2022-11-12 12:44:59浏览次数:74  
标签:11 13 07 int sum cdot 枚举 mathcal dp

2022/11/07-13 训练小记

P7961 [NOIP2021] 数列

显然是一个 \(dp\),首先考虑状态应如何设计。

看到 \(n\) 的限制,首先可以想到记一维 \(i\) 表示当前已被确定的 \(a\) 序列中的元素数量。

发现该题的难点在于从低位向高维的进位难以转移,因此我们可以从低位向高位考虑。

再开一维 \(j\) 表示当前考虑到了 \(S\) 的第 \(0\dots j\) 位,一维 \(p\) 表示第 \(0\dots j-1\) 向第 \(j\) 位的进位为 \(p\)。

注意 \(p\) 可以大于 \(1\),即第 \(j\) 位的进位暂且不以二进制形式写开。

由于还有\(S\) 的二进制表示中 \(1\) 不多于 \(K\) 的限制,所以再记一个 \(k\) 表示当前 \(S\) 的第 \(0\dots j-1\) 位中已有 \(k\) 个 \(1\)。

这个时候枚举一个 \(t\) 表示我们添加了多少 \(2^j\) 到 \(S\) 中 \((i+t\leq n)\),这样一来,如果 \(p+t\) 为偶数,第 \(j\) 位就会在处理掉第 \(j\) 位的所有进位后变成 \(0\);反之则为 \(1\)。所以 \((p+t)\bmod 2\) 的值即为处理掉第 \(j\) 位的进位后第 \(j\) 位是否为 \(1\)。又因为每两个 \(1\) 可以向下一位进一个 \(1\),所以第 \(j\) 位对第 \(j+1\) 位会有 \(\lfloor \dfrac{p+t}{2} \rfloor\) 的进位。

综上所述,我们设计状态 \(dp(i,j,k,p)\) 表示 \(a\) 序列中已确定了 \(i\) 个元素,当前考虑到了 \(S\) 的第 \(0\dots j\) 位,当前 \(S\) 的第 \(0\dots j-1\) 位中有 \(k\) 个 \(1\),第 \(0\dots j-1\) 向第 \(j\) 位的进位为 \(p\)。则 \(dp(i,j,k,p)\) 会向 $dp(i+t,j+1,k+(p+t)\bmod 2,\lfloor \frac{p+t}{2} \rfloor) $ 转移(枚举 \(t\in [0,n-i]\))。

由于答案满足分配律,不难想到 \(dp(i,j,k,p)\) 对新状态的贡献为

\[dp(i,j,k,p) \times {i+t\choose t}\times v_j^t \]

预处理一下组合数和 \(v_j\) 的幂次,即可做到 \(\mathcal{O}(n^4m)\) 转移。

转移的时候先枚举 \(j\) 再枚举 \(i\) 好像合理一些,但是先 \(i\) 后 \(j\) 也过了QwQ

那么如何统计答案呢?由转移的过程不难想到统计答案时需要枚举 \(dp(n,m+1,?,?)\),枚举 \(k,p\) 即可。

当 \(k+\mathrm{popcnt}(p)\leq K\) 时答案是合法的,因为第 \(m+1\) 位的进位还会让 \(S\) 中新增 \(\mathrm{popcnt}(p)\) 个 \(1\)。

\(\texttt{Main Code}\)

// 代码中交换了 i 与 j 的定义
for(int i=0;i<=m;++i){
	for(int j=0;j<=n;++j){
		for(int k=0;k<=K;++k){
			for(int p=0;p<=n;++p){
				for(int t=0;t<=n-j;++t)
					dp[i+1][j+t][k+(t+p&1)][t+p>>1]+=
                    dp[i][j][k][p]*C[j+t][t]%mod*pv[i][t]%mod;
			}
		}
	}
}
i64 ans=0;
for(int k=0;k<=K;++k){
	for(int p=0;p<=n;++p){
		if(k+popcnt(p)<=K) (ans+=dp[m+1][n][k][p])%=mod;
	}
}

P7140 [THUPC2021 初赛] 区间矩阵乘法

不难发现 \(d\) 的值域是根号级别的。猜想正解是一种 \(\mathcal{O}(n\sqrt n)\) 的做法。

先来化简一下要求的式子

\[\begin{align} \sum_{i=0}^{d-1} \sum_{j=0}^{d-1} \sum_{k=0}^{d-1} a_{p_1+d\cdot i+j} a_{p_2 + d\cdot j + k} &=\sum_{i=0}^{d-1}\sum_{j=0}^{d-1}a_{p_1+j+d\cdot i}\sum_{k=0}^{d-1}{a_{p_2+d\cdot j+k}}\\ &=\sum_{j=0}^{d-1}(sum_{p_2+d \cdot (j+1)-1}-sum_{p_2+d \cdot j-1})\sum_{i=0}^{d-1}{a_{p_1+j+d \cdot i}} \end{align} \]

如果使用同余前缀和(记 \(s_{i,j}\) 表示 \(\sum_{i=0}^{\lfloor \frac{j}{i} \rfloor}{a_{j-d \cdot i}}\) ),后面那个 \(\sum\) 可以用同余前缀和 \(\mathcal{O}(1)\) 求出。

暴力遍历 \(j \gets [0,d-1]\) 的复杂度是 \(\mathcal{O}(\sqrt n)\) 的,而 \(s\) 可以通过递推式

\[s_{i,j}=\left\{ \begin{array}{ll} a_j,j\leq i\\ s_{i,j-i}+a_j,j>i \end{array} \right. \]

\(\mathcal{O}(n\sqrt n)\) 预处理出。所以总时间复杂度 \(\mathcal{O}((n+m)\sqrt n)\);空间复杂度 \(\mathcal{O}(n\sqrt n)\),如果动态处理前缀和可以做到 \(\mathcal{O}(n)。\)

(最终的式子:\(\sum_{j=0}^{d-1}(sum_{p_2+d \cdot (j+1)-1}-sum_{p_2+d \cdot j-1})(s_{p_1+j+d(d-1)}-s_{p_1+j}+a_{p_1+j})\),这里的 \(sum_j\) 亦可写作 \(s_{1,j}\))

\(\texttt{Main Code}\)

void build(int n){
	int block=sqrt(n)+1;
	for(int i=1;i<=block;++i){
		for(int j=1;j<=n;++j){
			if(j<=i) s[i][j]=a[j];
			else s[i][j]=s[i][j-i]+a[j];
		}
	}
}
inline i32 query(int d,int p1,int p2){
	ans=0;
	for(int j=0;j<=d-1;++j) 
		ans+=(s[1][p2+d*(j+1)-1]-s[1][p2+d*j-1])*(s[d][p1+j+d*(d-1)]-s[d][p1+j]+a[p1+j]);
	return ans;
}	

P7145 [THUPC2021 初赛] 合法序列

看到 \(k\leq 4\) 和二进制,不难想到是一个状压 \(dp\)。

由于 \(2^k \leq 16\),所以可以先枚举第 \(0\dots2^k-1\) 位的数,对于其中合法的情况,记 \(dp(i,s)\) 表示当前考虑到第 \(i\) 位,以第 \(i\) 位为末尾的末 \(k\) 位为 \(s\) 的方案数。时间复杂度 \(\mathcal{O}(2^{2^k} \times 2^k \times n)\)。

\(dp(i,s)=dp(i-1,s>>1)[a_{s>>1}=1]+dp(i-1,(s>>1)|(1<<(k-1)))[a_{(s>>1)|(1<<(k-1))}=1]\)

\(\texttt{Main Code}\)

inline int calc(int x){
	int ret=0;
	for(int i=x;i<x+k;++i){
		ret<<=1;
		ret|=a[i];
	}
	return ret;
}
void solve(int x){
	for(int i=(1<<k)-1;i>=0;--i,x>>=1) a[i]=(x&1);
	for(int i=0;i<=(1<<k)-k;++i){
		int val=calc(i);
		if(a[val]==0) return;
	}
	memset(dp,0,sizeof(dp));
	dp[calc((1<<k)-k)][(1<<k)-1]=1;
	for(int i=(1<<k);i<n;++i){
		for(int s=0;s<(1<<k);++s){
			if(!a[s]) continue;
			if(a[s>>1]) dp[s][i]=dp[s>>1][i-1];
			if(a[(s>>1)|(1<<k-1)]) dp[s][i]+=dp[(s>>1)|(1<<k-1)][i-1];
			if(dp[s][i]>mod) dp[s][i]-=mod;
		}
	}
	for(int s=0;s<(1<<k);++s){
		if(!a[s]) continue;
		ans+=dp[s][n-1];
		if(ans>mod) ans-=mod;
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr);cout.tie(nullptr);
	cin>>n>>k;
	for(int i=0;i<(1<<(1<<k));++i) solve(i);
	cout<<ans;
}

好像有大佬用AC自动机上dp,我大受震撼


P7137 [THUPC2021 初赛] 切切糕

标签:11,13,07,int,sum,cdot,枚举,mathcal,dp
From: https://www.cnblogs.com/chroneZ/p/16883467.html

相关文章

  • 从 Ynoi2011 初始化 看卡常
    一般情况下,程序运行消耗时间主要与时间复杂度有关,超时与否取决于算法是否正确。但对于某些题目,时间复杂度正确的程序也无法通过,这时我们就需要卡常数,即通过优化一些操作的......
  • 周六900C++班级2022-11-12-搜索练习
    KnightMoves#include<bits/stdc++.h>usingnamespacestd;intnex[8][2]={{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}};//方向数组intvis[310][3......
  • 11.feign性能优化
    feign性能优化连接池配置,feign添加httpClient的支持1.引入依赖<!--httpClient的依赖--><dependency><groupId>io.github.openfeign</groupId>......
  • 13. 说一下$set,用在Vue2还是Vue3
    $set是vue2中对象用来追加响应式数据的方法;使用格式:$set(对象,属性名,值) vue3中使用proxy替代了Object.defineProperty实现对象的响应式数据,所以在......
  • #10077. 「一本通 3.2 练习 3」最短路计数
    问1~n的最短路有几个 #include<iostream>#include<cstring>#include<queue>usingnamespacestd;constintN=1e6+2,M=2e6+2;constintinf=0x3f3f3f3f,m......
  • 11. 跨域怎么解决
    首先,跨域分为开发环境和生产环境的跨域,我们在开发环境可以使用proxy代理给target设置请求接口地址,以前使用的是jsonp跨域;生产环境使用Nginx反向代理; 延申问......
  • P7137 [THUPC2021 初赛] 切切糕(博弈 概率)
    P7137[THUPC2021初赛]切切糕->双倍经验:GameonSum(HardVersion)有\(n\)块方蛋糕,绝顶聪明的Sight和Sirrel决定将每块蛋糕都分成两块各自品尝。Sight会依次......
  • 「题解」Codeforces 1342F Make It Ascending
    只会\(\mathcal{O}(3^nn^2)\),打开题解一看怎么还真是这个玩意/jy首先集合之间形成一个sum和pos的二维偏序,那么思路就是对一维扫描线,然后另一维搞个什么东西。具体到......
  • #10075. 「一本通 3.2 练习 1」农场派对
    图上每个点有一头牛,现在牛群聚集到点X上聚会,然后又回到各自的点,而且牛只走最短路径问所有最短路中最长的一条(路径包含来回) 正反跑一次 spfa(X), spfa(i), an......
  • #10074. 「一本通 3.2 例 3」架设电话线
    在加权无向图上求出一条从1号结点到N号结点的路径,使路径上第K+1大的边权尽量小 二分答案md,判断1~n是否存在一条路径,花费不超过md把w<=md的边看作0,否则看作1......