首页 > 其他分享 >CF Diary VII

CF Diary VII

时间:2023-07-02 11:36:23浏览次数:28  
标签:const LL VII CF Diary using mod 步数 define

7.2-
每 \(10\) 题一篇 \(\texttt{>o<}\) 。

7-1 1845E. AND Graph

\(\texttt{Difficulty:UnKnown}\)

题意

\(n(1\le n\le1500)\) 个 \(1\) 的 \(01\) 序列,每次可以将一个 \(1\) 挪到相邻的 \(0\) 上去,求恰好 \(k(1\le k\le1500)\) 次操作后,能有多少种不同的 \(01\) 序列。

题解

下设 \(n,k\) 同阶。
考虑无论如何操作最开始的 \(1\) 的相对次序都不会发生改变,记最开始每个 \(1\) 的位置为 \(a_i\) ,操作后的为 \(b_i\) ,于是最小操作步数为 \(\sum|b_i-a_i|\) ,如果一个方案的最小步数与 \(k\) 奇偶性相同,那么就是合法的方案,因为可以让一个 \(1\) 反复横跳来达到恰好 \(k\) 步。
一个比较容易想到的 \(\texttt{DP}\) 方法是记 \(f_{i,j,k}\) 表示前 \(i\) 个位置,放了 \(j\) 个 \(1\) ,最少步数为 \(k\) 的方案数,每次分情况放 \(1\) 与不放 \(1\) 向后转移,复杂度为 \(\mathcal{O}(n^3)\) ,考虑进一步优化。
考虑分别记 \(A_i,B_i\) 为操作前后 \(01\) 序列的前缀和, \(d_i\) 为前缀和的差值 \(B_i-A_i\) ,对于最小步数,我们可以统计每个 \(i\sim i+1\) 的区间的贡献来计算,即对于每个 \(d_i\) ,表示会有 \(|d_i|\) 个 \(1\) 在操作时需要通过 \(i\sim i+1\) 区间,于是最小步数为 \(\sum|d_i|\) 。因为总步数不能超过 \(k\) 的限制,而相邻两个 \(|d_i\) 至多差 \(1\) ,考虑 \(\sum|d_i|\) 的最小值即 \(\frac{(1+d_i)d_i}{2}\le k\) ,因此必然有 \(|d_i|\le\mathcal{O}(\sqrt k)\) ,于是可以把原来 \(\texttt{DP}\) 的第二维改为当前的 \(d_i\) 为 \(j\) ,这样第二维只用枚举至多 \(\mathcal{O}(\sqrt k)\) 个状态,于是复杂度 \(\mathcal{O}(n\sqrt n)\) 。

代码

view code
#include<bits/stdc++.h>
#include<unordered_map>
#include<unordered_set>
using namespace std;
using LL = long long;
using LD = long double;
using ULL = unsigned long long;
using PII = pair<LL, LL>;
using TP = tuple<int, int, int>;
#define all(x) x.begin(),x.end()
#define mst(x,v) memset(x,v,sizeof(x))
#define mul(x,y) (1ll*(x)*(y)%mod)
#define mk make_pair
//#define int LL
//#define double LD
#define lc p*2
#define rc p*2+1
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x3f3f3f3f3f3f3f3f
#pragma warning(disable : 4996)
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const double eps = 1e-8;
const double pi = acos(-1);
const LL mod = 1000000007;
//const LL mod = 998244353;
const int maxn = 1510;
LL N, K, A[maxn], f[2][130][maxn], h = 60;
void solve()
{
	f[0][h][0] = 1;
	for (int i = 1; i <= N; i++)
		A[i] += A[i - 1];
	for (int i = 1; i <= N; i++)
	{
		for (int j = -60; j <= 60; j++)
		{
			for (int k = 0; k <= K; k++)
			{
				f[i % 2][j + h][k] = 0;
				LL tj = j - (A[i - 1] - A[i]);
				if (k - abs(j) >= 0)
				{
					f[i % 2][j + h][k] = (f[i % 2][j + h][k] + f[(i - 1) % 2][tj + h][k - abs(j)]) % mod;
					f[i % 2][j + h][k] = (f[i % 2][j + h][k] + f[(i - 1) % 2][tj - 1 + h][k - abs(j)]) % mod;
				}
			}
		}
	}
	LL sum = 0;
	for (int i = 0; i <= K; i++)
	{
		if ((K - i) % 2 == 0)
			sum = (sum + f[N % 2][h][i]) % mod;
	}
	cout << sum << endl;
}

int main()
{
	IOS, cin >> N >> K;
	for (int i = 1; i <= N; i++)
		cin >> A[i];
	solve();
	return 0;
}

标签:const,LL,VII,CF,Diary,using,mod,步数,define
From: https://www.cnblogs.com/Prgl/p/17520470.html

相关文章

  • 7月CF杂题
    怎么七月了?六月的只写了一道题捏。EducationalCodeforcesRound151(RatedforDiv.2)俺寻思能行。D.RatingSystem为什么大家都切那么快捏。显然\(k\)一定是\(a\)数组的一个前缀和。假设\(k=\sum\limits_{i=1}^xa_i\),剩下的等价于处理初值为0且\(k=0\)的子问......
  • VCF(Variant Call Format)文件简介
    VCF(VariantCallFormat)文件是一种常用的存储基因组变异信息的文件格式。它是基于文本的格式,用于描述个体或种群的基因组中的单核苷酸变异(SNV)、插入/缺失(Indel)等变异类型。以下是VCF文件的一般结构和主要字段:1.文件元数据(Metadata):以`##`开头的行,用于描述VCF文件的元数据信息,如......
  • CF1804H Code Lock
    牛逼题,但是卡常。首先显然指针会从密码串第\(1\)个位置开始,因此我们需要关心的就是相邻两个位置的值。只需要求出\(c_{x,y}\)表示前一个是\(x\),后一个是\(y\)的个数即可。考虑一般的按顺序填的状压,总是避免不了顺序的问题,总是与\(k!\)有关,我们需要一个合适的计算贡献的......
  • CF1753 题解
    CF1753题解A首先我们发现,我们可以将序列一部分取反,将1变-1,-1变1的操作每次将总和增加2,所以如果初始和的绝对值为奇数则无解。我们发现,一段区间可以拆成若干个长度为2和1的小区间(+-+-+-+-....)变成(+-+-+-...)。我们假设初始都是长度为1的小区间,这时答案等于所有数的总和。我们......
  • CF1845C Strong Password
    思路这场edu爆炸了,特此记录。由于\(m\le10\),因此可以直接考虑搜索。对于定义状态为\((idx,cur)\),表示当前在填密码的第\(idx\)位,且使用了\(s\)中的前\(cur\)个字符。首先注意到对于同一个数字,如果其在\(s\)中出现了不止一次,那么出现在前边的显然比出现在后边的潜......
  • DCFW 透明模式
    首先配置PC的ip地址#绑定二层安全域。#创建虚拟交换机。右上角新建地址簿。#新建。#新建网段。#新建网段B。#放行策略。#两边都要放行策略。#这里就可以ping通了。相当于是划分vlan了。......
  • [CF1827F]Copium Permutation
    吓人题。一个显然的想法是对于\(k\),将贡献分为\(3\)类:\([1,k]\)子区间的贡献,\([k+1,n]\)子区间的贡献和跨过\(k\)的贡献。首先\([1,k]\)的贡献我们可以沿用PuddingMonsters的做法,从左往右枚举\(r\),统计\(r\)作为右端点的贡献。发现一个区间是Copium的当且仅......
  • CF1637H Minimize Inversions Number
    我直接??????????????????考虑一个数怎么做,就是逆序对减去一个\(i\)前面的逆序对再加上顺序对。考虑很多数怎么做,就是这个玩意的和再加上子序列种的顺序对减去逆序对,顺序对可以用逆序对表示,现在只考虑顺序对。注意到,如果\(i<j,p_i>p_j\)且\(i\)在子序列中\(j\)不在子序列中,那么把\(j\)弄......
  • Codeforces[CF1036B]Diagonal Walking v.2题解
    题目大意很明显,这道题就是求k步之内到达点\((a,b)\),然后尽量走对角线,求能走对角线的最大值。做题思路首先明白一个事实,即一个对角线可以通过增加一步而抵达点不变,如图:我们可以这样思考这道题,在到达目的地以后,剩余步数如果为双数,则在对角线来回走,最后会到目的地。但如果剩......
  • CF1843E Tracking Segments
    CF1843ETrackingSegmentsVP的时候本来摆烂了,结果快结束的时候想到了做法(没时间敲了qwq)。这里提供一种和已有题解不同的思路。我们发现,对于每个修改,我们可以将该点的值修改为这次修改的时间,未修改的点则赋为\(n+1\)。这样转化后,区间合法的条件就是区间内小于\(n+1\)的值至......