9月雜題

xishanmeigao發表於2024-09-11

[ABC310F] Make 10 Again

分母是 \(\prod a_i\),只需求分子。

首先要發現投出了 \(10\) 以上的點數是無用的,所以只需考慮 \(10\) 以內的。

思考如何計數,發現轉移依賴於前面的點數和的方案數,而且 \(10\) 很小,考慮狀壓 DP,設 \(f_{i,s}\) 表示前 \(i\) 個骰子,狀態為 \(s\) 的方案數,轉移不表。

\(s\leq M=2^{11}\),所以時間複雜度 \(\mathcal{O}(nM10^2)\)

[ARC174E] Existence Counting

怎麼就沒想到呢??一直想著直接計數,比較困難,正難則反,轉化為:排列數 \(-\) 沒出現 \(x\) 的排列數 \(-\) 字典序大於 \(P\) 的方案數 \(+\) 既沒出現 \(x\) 字典序還大於 \(P\) 的方案數。轉化後就比較基礎了。

[ARC173C] Not Median

感覺還是不夠。

直覺告訴我們,答案大多數都很小。

注意到答案很大的地方周圍應該長這樣 -+-+-+0-+-+-+,這告訴我們只需找到兩個相鄰的值又同時在 \(p_i\) 一側的就好了。

每個點都往左右掃,複雜度看似 \(\mathcal{O}(n^2)\),但是其實在 \(i\)\(x_1,x_2\) 之間的所有數答案一定是 \(3\),這意味著每個數只會被掃一遍。所以時間複雜度 \(\mathcal{O}(n)\)

[ABC281G] Farthest City

將所有點按最短路分層,每層的節點只能和相鄰層還有層內的節點連邊。設 \(f_{i,j}\) 表示用了 \(i\) 個點,最後一層有 \(j\) 個點的方案。轉移:

\[f_{i,j}=\sum\limits_{k=1}^{i-j}f_{{i-j},k}\times \dbinom{n-1-(i-j)}{j}\times 2^{\frac{j(j-1)}{2}}\times (2^k-1)^j \]

CF1476F Lanterns

典題,覆蓋問題可以將狀態設計成 \(f_i\) 表示前 \(i\) 盞燈能覆蓋的最長字首。

轉移分三類:

  • 前面不能覆蓋到 \(i\),直接不管 \(i\)\(f_i=f_{i-1}\)
  • 前面能覆蓋到 \(i\)\(f_i=\max(f_{i-1},i+p_i)\)
  • \(i\) 向左,找到一個 \(f_j\ge i-p_i\) 最小的 \(j\),然後 \(j+1\sim i-1\) 全部向右,\(f_i=\max\{k+p_k\}\)

不知道為什麼想這麼久,明明這麼簡單。

[ARC154C] Roller

有 ARC182B 作為基礎這題很容易想到做法,將相同的合併成一塊,只需判斷是否存在一個斷點使得 \(a\)\(b\) 的子序列。

但是還需要空餘的位置,可以是 \(a\)\(b\) 沒出現的,可以是 \(b\) 中相鄰的,也可以是 \(a\) 中相鄰的。若沒有空餘位置則必須 \(a,b\) 完全相等。

細節一直寫掛,陣列還開小了。

P3214 [HNOI2011] 卡農

想不出來。

\(f_i\) 表示選了 \(i\) 個子集且滿足條件的方案。考慮容斥,為了滿足和前面的 \(i-1\) 個子集加在一起全是偶數,前面每種選法都唯一確定一種子集,方案數為 \(A_{2^n-1}^{i-1}\)

再減去 \(i\) 為空的情況,方案數為 \(f_{i-1}\)(去掉 \(i\) 之後能滿足條件)。

再減去 \(i\) 和前面相同的方案。去掉 \(i\)\(j\) 後也能滿足條件,\(j\)\(i-1\) 種取值,子集 \(i\)\(2^n-1-(i-2)\) 種取法,方案數為 \(f_{i-2}\times (i-1)\times (2^n+1-i)\)

最後輸出 \(\dfrac{f_m}{m!}\)

P3577 [POI2014] TUR-Tourism

在無向圖搜尋樹上 DP,沒見過。

由題得樹的深度不超過 \(10\),這啟發我們用樹上狀壓 DP(還是沒見過)。

一個重要的性質:無向圖 DFS 樹上的非樹邊一定是回邊,不存在橫叉邊。所以我們可以狀壓父親的狀態。

DP 過程較為複雜,不寫。

P6381 『MdOI R2』Odyssey

透過質因數分解我們很容易判斷是否能構成完美數對,但是資訊在邊上我們很難直接 DP。

但我們發現如果用雜湊去表示每一條邊,那麼能與它配對的邊的雜湊值也是確定的。這啟發我們設 \(f_{i,h_i}\) 表示以 \(i\) 為終點,最後一條邊雜湊值是 \(h_i\) 的答案,時間複雜度 \(\mathcal{O}(n\log n\times 11)\)

P8860 動態圖連通性

很牛逼。

首先肯定要離線,然後多次詢問的邊只有第一次有用。

記邊被詢問的時間為 \(d_i\),沒詢問的視作 \(d_i=Q+1\)。將 \(d_i\) 作為邊的邊權,那麼就是要找一條路徑,使得將路徑上的邊的權值從大到小排序,字典序最小。

類似 「The classic problem」一樣用主席樹維護最短路。

CF464D World of Darkraft

需要注意到 \(k\) 種裝備地位相同,所以只需計算一種裝備最後乘 \(k\)。設 \(f_{i,j}\) 表示還剩 \(i\) 個怪獸,裝備等級為 \(j\) 的期望。轉移不表。

[ABC370F] Cake Division

不會倍增的菜鳥了屬於是。

二分答案,記 \(f_i\) 為從 \(i\) 開始的一個連續段的結尾 \(+1\)(即下一個連續段的開頭),那麼就是從 \(i\) 開始跳 \(k\)\(f\) 看終點是否滿足條件。這顯然倍增。

P7603 [THUPC2021] 鬼街

減半警報器。

一次靈異事件的發生可以暴力給所有質因子 \(+y\),因為質因子個數很少。問題是什麼時候統計答案。

對於一個 \((x,y)\) 的監控,記加入時其質因子已經發生了 \(s\) 次靈異事件,響警報的條件是 \(\sum\limits _{p}cnt_p\ge y+s\)。轉化成 \(\sum \Delta cnt_p\ge y\)。那肯定至少有一個 \(p\) 滿足 \(\Delta cnt_p\ge \lceil\frac{y}{d_x} \rceil\),我們將其設為閾值,當一個房間裡有監控達到閾值時我們就拿出來 check 一下,這可以用優先佇列實現。

如果 check 失敗,我們讓閾值變成 \(\lceil\frac{y-\sum\Delta cnt_p}{d_x} \rceil\),然後重新加入優先佇列。不難發現, 每次閾值至少減少 \(\dfrac{1}{d_x}\),所以時間複雜度 \(\mathcal{O}(m\times d_V\log V\log n)\)

[ARC171C] Swap on Tree

每棵子樹最多 \(siz+1\) 種取值,且新的數是什麼不重要。設 \(f_{x,t,0/1}\) 表示以 \(x\) 為根的子樹,與 \(x\) 相連的邊斷了幾條邊,和父親的邊是否斷了的方案數。

\(f'_{x,t,0}\leftarrow f_{x,t-1,0}\times f_{y,s,1}\times t+f_{x,t,0}\times f_{y,s,0}\)

\(f'_{x,t,1}\leftarrow f_{x,t-1,1}\times f_{y,s,1}\times t+f_{x,t,1}\times f_{y,s,0}\)

初始化 \(f_{x,0,0}=1\)\(f_{x,1,1}=[x\ne 1]\)

P6383 『MdOI R2』Resurrection

其實就是聯通塊的根之間連邊。

容易想到設 \(f_{x,i}\) 表示 \(x\) 上面還有 \(i\) 個點可供選擇的方案數,但是不會做轉移。

因為 \(x\) 的選擇會使得 \(i\) 的限制發生變化,而且 \(x\) 與兒子的誰先與父親切斷對轉移也有影響。平常的樹形 DP 依賴於兒子的狀態,而這裡對父親也提出要求。

考慮分析圖的性質,然後就發現兒子連的邊一定不會與父親連的邊交叉,要不連父親,要不連父親連的點的上面。分析出這點,然後就可以列舉父親連的點進行轉移了。

P6009 [USACO20JAN] Non-Decreasing Subsequences P

靜態區間查詢,考慮貓樹分治。

如何合併兩個前字尾資訊,記 \(g_{i,j}\) 表示 \([i,mid]\) 裡以 \(j\) 結尾的不下降子序列數量。將值域放到狀態裡即可合併。

P9716 [EC Final 2022] Coloring

先把環找出來,然後對於環上的每個點,以它為根對子樹進行 DP。

顯然每次覆蓋不會完全覆蓋上一次,那麼最後的覆蓋次數肯定是從子樹的上到下減小的,所以設 \(f_{x,i}\) 表示 \(x\) 覆蓋了 \(i\) 次的答案,轉移不表。

\(s\) 不在環上,則答案為 \(\max(f_{s,1},f_{s,2})\)

否則,我們對這個環進行考慮,手玩一下發現,最後以 \(s\) 為開頭按照邊的方向形成的節點序列的操作次數單調不升,且極差 \(\leq 2\),所以列舉最小值然後 DP。

有一些細節。

GJOI 9.11 T2

對於 \(01\)\(x\),一次操作指將其一個子串反轉(\(0\rightarrow 1\)\(1\rightarrow 0\)),定義 \(x\) 的權值為使得 \(x\) 滿足任意一對相鄰字元均不相同。

\(q\) 個詢問,每次詢問子串 \(s[l:r]\) 的所有非空子序列之和。

\(n,q\leq 5\times 10^6\)

\(w=\sum\limits_{i=1}^{n-1}[s_i\ne s_{i+1}]\),則 \(s\) 的權值為 \(\left\lceil\dfrac{w}{2}\right\rceil\)。這樣可以設計出 \(\mathcal{O}(n^2q)\) 的DP。使用貓樹最佳化可以做到 \(\mathcal{O}(n\log n+q)\)

但是題目要求線性,上述的 DP 沒有最佳化前途。

考慮將 \(\lceil\frac{w}{2}\rceil\) 拆成 \(\frac{1}{2}(w+[2\not\mid w])\),只需計算所有子序列 \(w\) 的和還有 \(w\) 為奇數的子序列個數。

  • 先計算前者,對於 \(l\le i<j\le r\)\(s_i=s_j\) 的字元,只有當它們同時出現在某個子序列且相鄰才有貢獻,則總貢獻為

    \[\sum\limits_{l\le i<j\le r,s_i=s_j}2^{r-l+i-j}\\=2^{r-l}\left(\sum\limits_{1\le i<j\leq r,s_i=s_j}2^{i-j}-\sum\limits_{1\le i<l,l\le j\le r,s_i=s_j}2^{i-j}-\sum\limits_{1\le i<j<l,s_i=s_j}{2^{i-j}} \right) \]

  • 再計算後者,有結論一個子序列 \(w\) 的奇偶性與等於子序列長度和 \([s_{st}=s_{ed}]\) 之和的奇偶性。

    對於 \(st\ge ed-1\),特判。

    對於 \(st< ed-1\),若 \(st,ed\) 固定,則長度為奇數的子序列和偶數相等,為 \(2^{ed-st-2}\)

    則總貢獻為

    \(\sum\limits_{l\le i<r}[s_i=s_{i+1}]+\sum\limits_{l\le i<j-1\le r}2^{j-i-2}\\=\sum\limits_{l\le i<r}[s_i=s_{i+1}]+\sum\limits_{2\le i\le r-l}2^{i-2}(r-l-i+1)\)

時間複雜度 \(\mathcal{O}(n+q)\)

GJOI 9.10 T2
#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=5e6+10,MOD=1e9+7;

int n,Q,opt,al,bl,ar,br,l,r;
LL res;
int pw[N],ipw[N],pre[N],s1[N],s2[N];
int A[N][2][2],B[N];
char s[N];

void addm(int &x,int y){(x+=y)%=MOD;if(x<0)x+=MOD;}

int ksm(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1) res=1LL*res*x%MOD;
		x=1LL*x*x%MOD;
		y>>=1;
	}
	return res;
}

void init()
{
	pw[0]=ipw[0]=1;
	for(int i=1; i<=n; i++)
		pw[i]=1LL*pw[i-1]*2%MOD;
	ipw[n]=ksm(pw[n],MOD-2);
	for(int i=n-1; i>=1; i--)
		ipw[i]=1LL*ipw[i+1]*2%MOD;
	for(int i=1; i<=n; i++)
	{
		if(i>1) pre[i]=pre[i-1]+(s[i-1]==s[i]);
		s1[i]=(s1[i-1]+pw[i-1])%MOD;
		s2[i]=(s2[i-1]+1LL*pw[i-1]*(n-i)%MOD)%MOD;

		bool cur=(s[i]=='1');
		B[i]=B[i-1];
		addm(B[i],1LL*ipw[i]*A[i-1][cur][0]%MOD);
		A[i][0][0]=A[i-1][0][0];
		A[i][0][1]=A[i-1][0][1];
		A[i][1][0]=A[i-1][1][0];
		A[i][1][1]=A[i-1][1][1];
		addm(A[i][cur][0],pw[i]);
		addm(A[i][cur][1],ipw[i]);
	}
}

int main()
{	
	freopen("alternate.in","r",stdin);
	freopen("alternate.out","w",stdout);

	scanf("%d%d%d%s",&n,&Q,&opt,s+1);
	if(opt) scanf("%d%d%d%d%d%d",&al,&bl,&ar,&br,&l,&r);

	init();

	for(int i=1; i<=Q; i++)
	{
		if(opt)
		{
			int tf=(1LL*al*l%n+bl)%n+1,tg=(1LL*ar*r%n+br)%n+1;
			if(tf>tg) swap(tf,tg);
			l=tf; r=tg;
		}
		else scanf("%d%d",&l,&r);
		int ans=0;
		addm(ans,B[r]); addm(ans,-B[l-1]);
		addm(ans,-1LL*(A[r][0][1]-A[l-1][0][1]+MOD)%MOD*A[l-1][0][0]%MOD);
		addm(ans,-1LL*(A[r][1][1]-A[l-1][1][1]+MOD)%MOD*A[l-1][1][0]%MOD);
		ans=1LL*ans*pw[r-l]%MOD;
		addm(ans,pre[r]-pre[l]); 
		addm(ans,s2[r-l-1]); addm(ans,-1LL*s1[r-l-1]*(n-r+l)%MOD);
		ans=1LL*ans*ipw[1]%MOD;
		if(opt) res^=(LL)(ans+i*23);
		else printf("%d\n",ans);
	}
	if(opt) printf("%lld\n",res);
	
	return 0;
}