Loading

2024 福建省队集训录

Day1

\(47+0+25=72\)rk.20,被 T1 给创了。

T1 (placement)

SourceP5225。赛事过了 \(1,3,4,7\) 这些点。Task 8 太困难了加上本菜鸡时间不充足,理解了下就贺了。

$\bf{solution}$
  • Task 1,暴力即可。

  • Task 2,考虑贪心加调整。每个问题选尽量优的 TPU ,即对每个问题,更优的 TPU 选择的概率更大一些。多调几次就过了。

  • Task 3,简单 dp,记 \(f_{i,x,y,z}\) 表示到 \(i\),三个机器内的和分别为 \(x,y,z\) 可不可行。数组上界取 .ans 中的 106 即可。

  • Task 4,简单 dp,记下上个点的颜色即可,注意 133,266 处有俩断点。

  • Task 5,赛事注意力涣散了,注意到每个点只和前 \(5\) 个点有关,且 \(k=5\)dp 记下前 \(5\) 个即可,复杂度 \(O(nk^6)\)

  • Task 6,同 Task 2 一样贪心,但是每个直接选最小的就过了,好逆天啊。

  • Task 7,注意到 \(m=0\),所有 \(t>1000\),但答案是 \(1014\),于是那么我们可以把不超过 \(1014\) 的时间当作边,二分图匹配输出方案即可。

  • Task 8,发现这个问题其实是一块一块的,\(1\)\(502\) 各独自是一块,中间每 \(50\) 个问题是一块,要计算下一块的任何问题,必须计算完上一块的所有问题。
    在块内,和 Task 7 一样,但是没有了时间限制,但显然时间限制是单调的,我们可以二分。
    观察到传输数据的时间都为 \(0/1\),而且显然是要传输数据的,所以块间耗时就是 \(1\),这是定值,不用考虑。
    但是,据 hhoppitree 所言,爬山能过。

  • Task 9/10,我赛事就没感觉到这个是 NP-Hard 的。退火/爬山/随机化/调整,感受那股劲。

按照 hhoppitree 的谆谆教诲写了爬山,跑起来挺优秀的啊,优秀性我不会论证。

updTask 9 可能饱和,请自行优化抽奖方式。

爬山
#include<bits/stdc++.h>
#define P pair<int,int>
#define fi first
#define se second
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define LL long long
using namespace std;
mt19937 rnd(time(0));
const int N=105;
int n,m,k,o,t[N][N],r[N][N],a[N],b[N],p[N],ans;
basic_string<int>g[N];
inline int get()
{
	int score;
	FILE *f=fopen("placement10.out","w");
	for(int i=1;i<=n;i++)
	{
		fprintf(f,"%d ",a[i]);
	}
	fclose(f);
	system("simulator.exe placement10.in placement10.out placement10.ans >fw.txt");
	FILE *g = fopen("fw.txt","r");
	fscanf(g,"%d",&score);
	fclose(g);return score;
}
int main()
{
	freopen("placement10.in","r",stdin);
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m>>k>>o;
	for(int i=1,u,v;i<=m;i++) cin>>u>>v,g[u]+=v;
	for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) cin>>t[i][j];
	for(int i=1;i<=k;i++) for(int j=1;j<=k;j++) cin>>r[i][j];
	for(int i=1;i<=n;i++) a[i]=b[i]=rnd()%k+1;ans=get();
	while(1)
	{
		int w=rnd()%n+1,x=rnd()%k+1,las=a[w];
		a[w]=x;int nw=get();
		if(nw<ans)
		{
			ans=nw;memcpy(b,a,sizeof(a));
			cerr<<nw<<"\n";
			if(ans<=5142063) return 0;
		}
		else a[w]=las;
	}
	return 0;
}//5142063

T2 (cchoing)

Sourceuoj #427

你先别急

T3 (meeting)

Sourceuoj #705

容易发现公差为 \(k\) 的等差数列可以写成 \(k^{-1}\) 个公差为 \(1\) 的等差数列的并。

证明就考虑 \(ak+b\)\(a\) 拆成 \(pk^{-1}+r\) 然后取模考虑即可。

\(k\) 拆成 \(\frac{X}{Y}\) 其中 \(X,|Y|\in [1,\sqrt p]\),可以证明一定存在这样的拆法。

然后对于每个 \(X\) 单独处理询问,每个询问看成求 \(\frac{1}{Y}\times X\times (i+s\times X^{-1})\),其中 \(s=x+k-1\) 是起点,\(i\in [0,l-1]\)

\(b_i=a_{iX}\) 然后做前缀和,对于 \(Y\) 查询这 \(Y\) 个连续段的和即可。复杂度单根号。

\(\bf{record}\)


Day2

预期得分:\(100+10+0=110\),实际得分:\(35+2+0=37\)rk.33

T1 忘记判 \(-1\) 挂了 65 分,警钟长鸣!今天搬了三道集训队胡策的题。

T1 (compete)

Sourceqoj 5034

$\bf{solution}$

正解请看这篇!往下翻翻就找到了。下文为假做法/不会证明正确性的做法。但是是自己的全流程思路还是记录一下。


考虑把路径的限制转化到 ACAM 上,即把路径看着一个字符串插入 trie 树并建立 ACAM。参考 hdu 4511

考虑这时候在跑 dij 的时候多记一个状态表示当前在 ACAM 上的哪个点,然后 ACAM 上那些路径结尾的点不能走。

建完 ACAM 接着 dij 转移的时候另一维变成 nex 即可。

这时设路径长为 \(L\),不妨设 \(n,m,L\) 同阶,则复杂度为 \(O(n^2)\)。考虑优化。


首先,建 ACAM 时参考 「ACAM 解决字符集很大的情况」,上一个可持久化数组加 unordered_map 即可。

然后考虑 dij 转移,发现大部分情况下 ACAM 上的点唯一对应原图上的点,除了 trie 树的根(其可能对应 \(n\) 个点)。

那么我们就可以把原来 \(O(n^2)\)dis 状态优化到了 \(O(n)\)到这里的 record

  • 以上是赛时成果,不仅没判 \(-1\) 寄了,复杂度其实也是假的。

下文感谢伟大的 Nesraychan 的指导!(其实也是假做法)

注意到一个问题:此时原图上的一个点可能被很多个 ACAM 上的点对应,在遍历其的出边时候就有可能遍历 \(O(mL)\) 条边。

ACAM(或理解为 trie 树) 的根为 \(0\) 号点。

注意到初始走没路径限制的边一定更优,于是走到 \(0\) 号点的边在 vector 中遍历过一次后就可以删去。

注意到 \(0\) 号点对应的点很多,比较关键,反正跑很快,而且短小精悍,自信能过(bushi)。讲得有点抽象,具体看代码。

\(\bf{record}\)

T2 (soul)

SourceP9056

你先别急。

T3 (line)

Sourceqoj 5017

你先别急。


Day3

预期得分:\([20,40]+50+10=[80,100]\),实际得分:\(40+50+0=90\)rk.26

T1 没认真思考,最后卡卡常多捡了点分。T2 不应该做不出来的。

T1 (fish)

SourceCF1090H,输入格式略有不同。

简要题意

我们称一个长度为 \(2^k\)\(01\)\(s\) 是好的当且仅当:

存在 \(0 \le x < 2^k,b \in \{0, 1\}\) 满足 \(\forall 0 ≤ i < 2^k, s_i = \text{parity}(i\ \text{and}\ x)\ \text{xor}\ b\)

其中 parity 表示一个数字二进制下 \(1\) 个数的奇偶性(即:\(\text{popcount} \bmod 2\))。

对于一个字符串,你可以进行若干次操作,将它的一个子区间反转,即把 \(0\) 变为 \(1\)\(1\) 变为 \(0\)

给定一个长度为 \(n\) 的字符串 \(S\),进行 \(q\) 次询问,每次查询 \(S_{[l,r]}\) 需要进行多少次区间反转操作才能变成好的。

要求做到 \(O(n\log n)\)

$\bf{solution}$

实在理解不能了,转载了 Itst 的题解。

首先注意到对于串 \(s\)\(b = s_0\) 一定会比 \(b = s_0 \oplus 1\) 更优。

考虑先分析 linear 串的性质。注意到位运算 \(\oplus\) 考虑按位处理。我们考虑 \(x\) 的最高位,如果 \(x\) 的最高位为 \(1\),那么 linear 串的前后两半的异或和为 \(0\),否则前后两半完全相等。那么可以得到一个重要的性质:对于一个 linear 的串,将其分为前半段和后半段,前半段和后半段要么相等,要么完全不同,对于前后两半段还需递归满足这个条件。

好像有这个性质也没有什么用,但是注意到每一次的修改是区间取反,这在差分数组 \(\oplus\) 上会体现为两个位置的修改,比较方便。所以我们考虑差分处理。我们不妨分析一下差分之后 linear 串的性质。设 \(t_i = s_i \bigoplus s_{i-1}, i \in [1, |s|]\)。对于差分数组 \(t\),因为 \(s\) 的前半段和后半段相等,所以差分数组除了 \(\lfloor \frac{|s|}{2} \rfloor\) 的位置可以随意取值,剩下的由 \(\lfloor \frac{|s|}{2} \rfloor\) 分开的两个差分数组对应位置相等,且分开得到的两个差分数组还需递归满足这个性质。

我们对于给出的 \(01\) 串进行差分,对于一个询问 \([l, r]\) 只需要将 \([l + 1, r]\) 的差分数组用尽可能少的单点取反变为一个满足 linear 串差分数组性质的数组 \(\bigoplus\)。注意到 linear 串差分数组的性质是一些位置的值相等,我们可以把这些值拿出来,用 \(\min\{cnt_0, cnt_1\}\) 贡献答案,这样可以做到 \(O(nq)\)

最后需要考虑如何快速求出一个连通块内 \(0/1\) 个数。不难发现对于所有 lowbit 相等的位置会形成一个连通块 (这个可以考虑所有 lowbit 相同的点,然后考虑自底向上时的连边情况,不难发现这些点连成一棵树且没有往外连边),然后记一下前缀和 \(\bigoplus\) 计算对于 lowbit 相等的所有位置的 \(1\) 的个数即可。

\(\bf{record}\)

T2 (gardenia)

SourceDELARR

简要题意

对于一个序列 \(a\),可以对其进行若干次操作,每次选择两个相邻的不同的数一并删除。

请求出所有长度为 \(n\) 的值域在 \([1, m] \cap \mathbb{Z}\) 的序列的所有子区间(共 \(m^n \times \begin{pmatrix} n+1 \\ 2 \end{pmatrix}\) 个)中有多少个能够通过上述操作被删空。答案对 \(998244353\) 取模。

\(n\le 10^6,m\le 10^9\)

$\bf{solution}$

前置题目高橋君

\(f_n\) 表示长度为 \(n\) 的能被删空的序列,则答案为 \(\sum\limits_{1\le 2k\le n} (n-2k+1)T_{2k}\)

观察能被删空的条件,容易发现这当且仅当其没有绝对众数。考虑容斥,枚举绝对众数的个数:

\(T_{2n}=m^{2n}-m\sum\limits_{k=n+1}^{2n} \dbinom{2n}{k}(m-1)^{2n-k}=m^{2n}- m\sum\limits_{k=0}^{n-1} \dbinom{2n}{k}(m-1)^{k}\)

  • 其中 \(m\) 表示绝对众数有 \(m\) 种选择方案,然后从 \(2n\) 个数种选 \(k\) 个绝对众数,剩下数任意填。

\(a=m-1,f(n)=\sum\limits_{k=0}^{\lfloor n/2\rfloor} \dbinom{n}{k}a^{k}\),我们只需递推出 \(f(0,1,\cdots,n)\) 即可快速计算 \(T\)

参考前置题目的方法,有考虑 \(n\to n+1\) 拆组合数。令 \(d(n+1)=[2\nmid n]\dbinom{n+1}{(n+1)/2}\)

\(\begin{aligned}f(n+1)&=d(n+1)+\sum\limits_{k=0}^{\lfloor n/2\rfloor} \dbinom{n+1}{k}a^{k}\\ &=d(n+1)+\sum\limits_{k=0}^{\lfloor n/2\rfloor} \left(\dbinom{n}{k}+\dbinom{n}{k-1}\right)a^{k}\\ &=d(n+1)+\sum\limits_{k=0}^{\lfloor n/2\rfloor} \dbinom{n}{k}a^k+a\sum\limits_{k=0}^{\lfloor n/2\rfloor-1}\dbinom{n}{k}a^{k}\\ &=d(n+1)+(a+1)f(n)-\dbinom{n}{\lfloor n/2\rfloor}a^{\lfloor n/2\rfloor+1}\end{aligned}\)

递推即可,实现精细能做到线性,我写了 \(O(n\log n)\),中间用了快速幂。

$\bf{code}$
#include<bits/stdc++.h>
#define LL long long
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
using namespace std;
const int N=1e6+5,M=N-5,mod=998244353;
int T,n,m,jc[N],inv[N],f[N];
inline int rd()
{
	int x=0,zf=1;char ch=getchar();
	while(ch<'0'||ch>'9') (ch=='-')and(zf=-1),ch=getchar();
	while(ch>='0'&&ch<='9') x=(10*x+ch-'0'),ch=getchar();
	return x*zf;
}
inline void wr(int x)
{
	if(x==0) return putchar('0'),putchar('\n'),void();
	int num[35],len=0;
	while(x) num[++len]=x%10,x/=10;
	for(int i=len;i>=1;i--) putchar(num[i]+'0');
	putchar('\n');
}
inline int md(int x){return x>=mod?x-mod:x;}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
inline int C(int n,int m){return n<m?0:1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
inline int F(int A,int B){return 1ll*C(A,B)*ksm(m-1,B)%mod;}
int main()
{
	T=rd();for(int i=jc[0]=1;i<=M;i++) jc[i]=1ll*jc[i-1]*i%mod;
	inv[M]=ksm(jc[M],mod-2);for(int i=M-1;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
	while(T--)
	{
		n=rd(),m=rd();int ans=0;f[0]=1;
		for(int i=0;i<n;i++)
			f[i+1]=((i&1)*F(i+1,(i+2)/2)+f[i]+1ll*(m-1)*(f[i]-F(i,i/2)+mod))%mod;
		for(int i=2;i<=n;i+=2)
			ans=(ans+(ksm(m,i)+1ll*(f[i]-F(i,i/2)+mod)*(mod-m))%mod*(n-i+1)%mod*ksm(m,n-i))%mod;
		wr(ans);
	}
	return 0;
}

T3 (camera)

简要题意

交互题。有 \(n\) 张卡牌,其中卡牌花色从 \(1\sim n/2\) 编号,每种卡牌分别有两张。

你每次可以选择其中两张牌,得知它们的花色分别是什么,然后它们会在随机交换或不交换后放回原位。

你需要在 \(L\) 次翻看内确定所有牌的具体花色。

测试点中 \((n,L)=(10,100),(10^3,960),(10^4,9450),(10^5,92000)\)

你先别急。


Day4

\(100+25+5=130\)rk.22

T1 (aw)

SourceCF1770E。改编了。

注:CF 那题与本题有点细节上的不同,但整体思想/思路都是一致的。

简要题意

给定一棵 \(n\) 个结点的树,结点 \(w\)\(a_w\)aw

定义一组给所有 \(n - 1\) 条边定向的方案的权值为:按输入顺序依次考虑每条边 \(u \rightarrow v\),将结点 \(u\)aw 全部移动至结点 \(v\),最终每两个 aw 所在结点之间的距离之和。两个结点之间的距离为它们在树上的最短路径经过的边数。

求所有 \(2^{n-1}\) 组方案的权值之和,对 \(998244353\) 取模。

\(2\le n\le 10^5,0\le a_w<998244353\)

$\bf{solution}$

考虑把路径的期望转化为每条边被选中的期望。然后注意到每条边较为独立,然后观察贡献形式,维护一次方和和二次方和就过了。

自己思路太复杂,不想写题解啦!贺一篇。


考虑将贡献均摊至每一条边。

按顺序处理每一条边 \((u, v)\),并且在处理该边时计算其产生的贡献:

  • 考虑每条边产生的贡献关于所有定向方案(而不是所有定向方案和选点方案)的期望,最后乘以 \(2^{n-1}\)
  • \(p_{u,x}\) 表示当前点 \(u\)\(x\)aw 的概率。
  • 预处理求得 \(u, v\) 两侧原来的 aw 数量 \(c_u, c_v\)
  • 若定向为 \(u \rightarrow v\),则产生贡献 \(\sum_x p_{u,x} (c_u - x) (c_v + x)\),乘以概率 \(\frac{1}{2}\)
  • 若定向为 \(v \rightarrow u\),则产生贡献 \(\sum_x p_{v,x} (c_u - x) (c_v + x)\),乘以概率 \(\frac{1}{2}\)

直接维护 \(p\) 太难受了,考虑到我们不关心具体的每个 \(p_{u,x}\),而是 \(\sum p_{u,x} x\)\(\sum p_{u,x} x^2\),所以分别设 \(f_u, g_u\) 维护之。\(f_u\) 就是 \(u\) 含有 aw 数量的期望值。

这样,\(u \rightarrow v\) 的贡献式可写为:\(c_u c_v \sum_x p_{u,x} + (c_u - c_v) \sum_x p_{u,x} x - \sum_x p_{u,x} x^2\)

\(c_u c_v + (c_u - c_v) f_u - g_u\) 再乘以 \(\frac{1}{2}\)\(v \rightarrow u\) 同理。

接下来只要维护 \(f\)\(g\)

显然,处理当前边时,不会影响到除了 \(u, v\) 以外其它所有点的 \(f\)\(g\)

对于 \(f_u\),它会变成 \(\frac{1}{2} \sum_{x,y} p_{u,x} p_{v,y} (x + y)\),拆一下就是 \(\frac{1}{2} (f_u + f_v)\)。这个式子很合理,因为随机定向使得 aw 均匀分布在这两个点上。\(f_v\) 同理应该等于 \(f_u\) (从式子的对称性也可以理解)。

对于 \(g_u\),它会变成 \(\frac{1}{2} \sum_{x,y} p_{u,x} p_{v,y} (x + y)^2\),拆一下就是 \(\frac{1}{2} (g_u + g_v + 2 f_u f_v)\)\(g_v\) 同理等于 \(g_u\)

时间复杂度 \(O(n)\)

$\bf{code}$
#include<bits/stdc++.h>
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define LL long long
using namespace std;
const int N=1e5+5,mod=998244353;
int n,a[N],b[N],c[N],d[N],S[N],s,ans,pw[N],f[N];
struct node{int u,v;}E[N];
basic_string<int>g[N];
inline int md(int x){return x>=mod?x-mod:x;}
inline void ad(int &x,int y){x=md(x+y);}
inline int ksm(int x,int p){int s=1;for(;p;(p&1)&&(s=1ll*s*x%mod),x=1ll*x*x%mod,p>>=1);return s;}
void dfs(int x,int fa){f[x]=fa;S[x]=a[x];for(int i:g[x]) if(i^fa) dfs(i,x),ad(S[x],S[i]);}
int main()
{
    // fr(aw)
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n;
    for(int i=pw[0]=1;i<=n;i++) cin>>a[i],ad(s,a[i]),pw[i]=md(pw[i-1]<<1);
    for(int i=1,u,v;i<n;i++) cin>>u>>v,E[i]={u,v},g[u]+=v,g[v]+=u;
    dfs(1,0);for(int i=1;i<=n;i++) b[i]=1ll*a[i]*a[i]%mod,c[i]=1;
    for(int i=1;i<n;i++)
    {
        auto [u,v]=E[i];if(f[v]==u) swap(u,v);
        int x=a[u],y=a[v],X=b[u],Y=b[v],S1=S[u],S2=md(s+mod-S1),S3=(1ll*X*c[v]+1ll*Y*c[u])%mod,
        A=1ll*x*c[v]%mod,B=1ll*y*c[u]%mod,C;
        a[u]=a[v]=md(A+B);b[u]=b[v]=(S3+2ll*x*y)%mod;
        C=2ll*c[u]*c[v]%mod;c[u]=c[v]=C;d[u]=d[v]=d[u]+d[v]+1;
        ans=(ans+(mod-S3+1ll*C*S1%mod*S2+1ll*(S1-S2+mod)*(A-B+mod))%mod*pw[n-1-d[u]])%mod;
    }
	return cout<<(ans+mod)%mod,0;
}

CF 那题的 record

T2 (awa)

简要题意

\(T\) 组多测。给定两个由小写字母组成的字符串 \(s,t\)

求有序二元正整数对 \((x, y)\) 的数量,满足 \(1\le x,y\le n\),且 \(s\) 的长度为 \(x\) 的前缀和长度为 \(y\) 的后缀拼接得到的字符串是 \(t\) 的子串。

这里,拼接表示将后一个字符串拼在前一个字符串之后。

  • \(1\le T\le 10,1\le |s|,|t|\le 2\times 10^5\)

你先别急。

T3 (awaw)

简要题意

Sourceqoj 4417

\(m\times m\) 的网格上有 \(n\) 个矩形,第 \(i\) 个矩形覆盖了 \(a_i\le x \le a_i + w − 1\)\(b_i \le y \le b_i + h − 1\) 的所有格点 \((x, y)\)

求没有被覆盖的格点形成的所有四连通块的大小的平方和。对 \(2^{64}\) 取模。多测。

注:\(w,h\) 全局是固定的。

  • \(\sum n\le 5\times 10^6,1\le w,h\le m\le 10^9\),保证输入矩阵不超过边界。

你先别急。


Day5

预期得分:\([45,100]+16+20=[81,136]\),实际得分:\(75+16+20=111\)rk.42。菜!

T1 (arithmetic)

Sourceqoj 7877

$\bf{solution}$

对于每个 \(k\),容易发现满足条件的前缀一定形如一个区间 \([2k+1,r_k]\),于是问题转化为 \(\forall k\),求 \(r_k\)

考虑如何判断前缀 \([1,l]\)\(k\) 时是否合法,字符串哈希一下,发现转化为 \(\bf{hash}(1,l-2k)+\bf{hash}(2k+1,l)=2\bf{hash}(k+1,l-k)\),预处理哈希值后可 \(O(1)\) 判断。

此时直接二分 \(r_k\) 就可做到 \(O(n\log n)\) 了。

考虑从大到小枚举 \(k\) 的过程中,记 \(p=\max\{r_1,r_2,\cdots r_{k-1}\}\),于是此时 \(<p\) 的端点就不需要再枚举了,直接从 \(\max(p,2k+1)\) 开始枚举即可。

预处理下哈希值,端点移动总次数是线性的,于是总复杂度 \(O(n)\)

\(\bf{record}\)

T2 (cross)

简要题意

Source:hdu 6541

在平面直角坐标系 \(Oxy\) 上有 \(n\) 个点 \(A_1,A_2,\cdots ,A_n\)

\(m\) 次询问,每次询问给出一个点 \(P\),请找到区间 \([l, r]\),使得 \(\sum\limits_{i=l}^r \overrightarrow{OP}\times \overrightarrow{OA_i}\) 最大,并输出这个最大值。

注意这里 \(\overrightarrow{OP}\times \overrightarrow{OA_i}\) 是个标量,表示向量叉积的值。

  • \(1\le n\le 10^5,1\le m\le 10^6\),所有坐标绝对值不超过 \(10^5\)

你先别急。

T3 (transform)

Sourceqoj 1262

简要题意

给定数列 \(a_1, a_2,\dots , a_n\),保证 \(a_i\) 互不相同,你可以进行如下操作任意次:

  • 选取 \(1 \le i < j \le n\),将 \(a_i, a_j\) 加一。操作完毕后 \(a_i\) 仍然需要互不相同。

又给定数列 \(b_1, b_2,\dots , b_n\),保证 \(b_i\) 互不相同,请问有多少种操作序列能够将 \(a_1, a_2, \dots , a_n\) 变成 \(b_1, b_2, \dots , b_n\)

\(998244353\) 取模的结果。

\(2\le n\le 30,1\le a_i,b_i\le 200\)

$\bf{solution}$

无解情形: \(a_i > b_i\)\(\sum\limits_{i=1}^{n} (b_i - a_i)\) 是奇数或 \(a_i > a_j\)\(b_i < b_j\)

考虑如果没有操作过程中 \(a\) 中的元素两两不同的限制怎么做。令 \(d_i = b_i - a_i\),那么显然需要操作 \(t = \frac{\sum d_i}{2}\) 次,加一的总次数是 \(2t\)。于是有一个想法是把这 \(2t\) 次加法分配到每个位置,也就类似 \(\dfrac{1}{2^t}\dbinom{2t}{d_1, d_2, \dots, d_n}\)

但是这个式子考虑的还不够,因为我们每次操作选择的位置应该是不同的,这么算法会算入选择相同位置的情况。

既然很难处理没有,不如用容斥钦定有,那么枚举钦定选择相同位置的数量 \(s\),以及每个位置被同时选择的次数 \(c_i\),可以得到

\(\dfrac{1}{2^t} \sum\limits_{s=0}^{t} (-1)^s\dbinom{t}{s} \sum\limits_{c_1 + \dots + c_n = s} \dbinom{s}{c_1 \dots c_n} \dbinom{2t - 2s}{d_1 - 2c_1, \dots ,d_n - 2c_n}\)

注意到这里的 \(\dfrac{1}{2^t}\) 是说同一次操作内是没有先后顺序的,提出常数后可以用背包求解。

上面的背包可以抽象成若干个多项式乘起来,且每个多项式只与 \(d_i\) 有关。写成这样:

\(\dfrac{1}{2^t} \sum\limits_{s=0}^{t} (-1)^s\dbinom{t}{s} s! (2t - 2s)! [x^s] \prod\limits_{i=1}^{n} \sum\limits_{j=0}^{d_i / 2} \dfrac{x^j}{j! (d_i - 2j)!}=\dfrac{t!}{2^t} \sum\limits_{s=0}^{t} (-1)^s\dfrac{(2t - 2s)!}{(t-s)!}[x^s] \prod\limits_{i=1}^{n} P_{d_i}\)

其中 \(P_d=\sum\limits_{j=0}^{d/2} \dfrac{x^j}{j! (d - 2j)!}\)

问题要求操作的过程中互异,怎么办?

考虑如何处理不能相同的情况。如果我们把每个值抽象成一个点,相当于找若干条路径,路径每层中不能有交点,一组路径 \(i \rightarrow j\) 的权值为 \(P_{b_j - a_i}\),总权值为所有路径权值乘积的情况下所有合法路径的权值和。

上述特征与 LGV 引理的描述非常相似,于是我们考虑用 LGV 引理计算答案。具体的,我们构造矩阵

\(M = \begin{bmatrix} P_{b_1 - a_1} & P_{b_2 - a_1} & \dots & P_{b_n - a_1} \\ P_{b_1 - a_2} & P_{b_2 - a_2} & \dots & P_{b_n - a_2} \\ \vdots & \vdots & & \vdots \\ P_{b_1 - a_n} & P_{b_2 - a_n} & \dots & P_{b_n - a_n} \end{bmatrix}\)

那么我们要求的答案多项式就是 \(\det(M)\),时间复杂度 \(O(n^3 t^2)=O(n^5D^2)\),其中 \(D=\max(d_i)\),能有很高的分数。

考虑优化上述算法。注意到瓶颈在于计算行列式中的多项式乘法。使用拉格朗日插值。因为最终多项式次数是 \(O(t)\) 的,所以我们不再在行列式中计算多项式,而是随便选 \(O(t)\) 个数带入矩阵中每个多项式算出点值,然后用点值算行列式。

最后使用拉插公式将多项式还原。即暴力拆拉插的公式。时间复杂度 \(O(tn^3+t^2)=O(n^4D+n^2D^2)\)

一个小细节是行列式多项式那里需要记忆化一下 \(P_{*}(x)\),否则可能会退化为 \(O(n^2t^2)=O(n^4D^2)\)

\(\bf{record}\)


Day6

理想情况 \(0+100+10=110\)T2 没调出来销号了。致敬传奇删号王!

T1 (cormorant)

SourceP5998

简要题意

\(n\le 10^5\) 个各边平行于坐标轴的矩形。

如果两个矩形的公共面积 \(>0\),那么这两个矩形就会合并成各边平行于坐标轴且能完全包含原来两个矩形的最小矩形。

当所有合并完成后,输出最终所有矩形的位置。

你先别急。

T2 (snowfinch)

Sourceqoj 888\(n=2\) 的弱化版:ARC158E

$\bf{solution}$

考虑分治,若 \(l<r\),记 \(mid\) 表示 \([l,r]\) 中点,则 一条 \((l,o_1)\sim(r,o_2)\) 的路径一定跨过 \(mid\)

假设我们已经求出了 \(f_{i,j,k}\) 表示中点线的第 \(k\)\((mid/mid+1,k)\) 到点 \((i,j)\) 的最短路。

那么此时跨过中点的答案:\(\sum\limits_{i=l}^{mid}\sum\limits_{j=mid+1}^r \sum\limits_{o=0}^2 \sum\limits_{p=0}^2\min\limits_{q=0}^2 (f_{i,o,q}+f_{j,p,q})\)

发现可以枚举 min\(p\) 取多少,然后做 \(3\) 次二维偏序算贡献,再加上分治的 \(\log\) 复杂度为 \(O(m\log^2 m)\)


接下来考虑如何求最短路以及分治到 \(l=r\) 的情况。

首先 \((x,0)\sim (x,1)\) 以及 \((x,1)\sim (x,2)\) 的最短路显然是它们俩的权值和。

考虑 \((x,0)\sim (x,2)\) 的情况,发现由于 \(n=3\),于是可能存在如下情况:

写个前缀和然后写个前/后缀 min 即可。

最短路最朴素的想法是直接把 \([l,mid]\) 的点拎出来跑以 \((mid,0/1/2)\) 为源点的单源最短路,但发现可能存在如下更优情况:

处理方式也很简单,只需要在最左侧加上一条 \((l,0)\sim (l,2)\) 且边权为其更左侧最优的 \(w'\) 的边,然后跑 dij 即可。

右侧同理,\(w'\) 是容易通过之前预处理的前/后缀 min 得到,就做完了,dij 复杂度和偏序一致,于是复杂度不变,为 \(O(m\log ^2 m)\)

\(\bf{record}\)

T3 (tern)

Source高橋くんの帰還

你先别急。


Day7

预期得分 \(100+15+[?]=115+[?]\),实际得分 \(100+5+5=110\)rk.37

T1 (densha)

简要题意

给定 \(n\),计算有多少个 \(1\sim n\) 的排列满足积性函数性质。即 \(\forall 1\le i,j,ij\le n,a_{ij}=a_ia_j\)

\(T\) 组多测,对 \(998244353\) 取模。

  • \(T\le 10^4,1\le n\le 10^7\)
$\bf{solution}$

容易通过打表找规律/打表 oeis/代数推导发现:另 \(S_d=\{p:p\le n,p\in \text{Prime},\lfloor n/p\rfloor=d\}\),则 \(ans=\prod\limits_{d} (|S_d|!)\)

线性筛出素数后再整除分块计算即可,复杂度 \(O(n+T\sqrt n)\)

注:此数列在 OEIS 上为 A357328

$\bf{code}$
#include<bits/stdc++.h>
#define fr(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);
#define LL long long
using namespace std;
const int N=1e7+5,mod=998244353;
int T,n,pr[N/10],jc[N],s[N];bool v[N];
inline void init(int M)
{
	for(int i=2;i<=M;i++)
	{
		if(!v[i]) pr[++pr[0]]=i;
		for(int j=1;j<=pr[0]&&i*pr[j]<=M;j++)
		{
			v[i*pr[j]]=1;
			if(i%pr[j]==0) break;
		}
	}
    for(int i=jc[0]=1;i<=M;i++) jc[i]=1ll*jc[i-1]*i%mod;
    for(int i=1;i<=pr[0];i++) s[pr[i]]++;
    for(int i=1;i<=M;i++) s[i]+=s[i-1];
}
int main()
{
    // fr(densha)
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>T;init(N-5);
    while(T--)
    {
        cin>>n;int ans=1;
        for(int i=1,j;i<=n;i=j+1) j=n/(n/i),ans=1ll*ans*jc[s[j]-s[i-1]]%mod;
        cout<<ans<<"\n";
    }
	return 0;
}

T2 (hacho)

简要题意

Sourceqoj 4215

对于一个序列 \(a\),可以对其进行若干次操作,每次将一个数减少 \(1\)

定义 \(f_k\) 表示进行 \(k\) 次操作后序列的最大子段和最小能达到多少。

给定 \(a, K\),计算 \(\sum\limits_{k=1}^K f_k\),答案对 \(998244353\) 取模。

  • \(1\le n\le 10^5,1\le K\le 10^{13},|a_i|\le 10^8\)

你先别急。

T3 (hokaku)

SourceAT wtf22 day2 c

你先别急。

posted @ 2024-07-06 19:14  HaHeHyt  阅读(311)  评论(0)    收藏  举报