WC2022 雜題選講 鄧明揚

2022-09-19 16:12:13 字數 2805 閱讀 3692

題目描述

一顆星星可以抽象成 \(k\) 維空間中的乙個整點。稱若干星星構成的集合 \(s\) 是奇妙的,當且僅當存在 \(k\) 維空間中的整點 \(p\),\(p\) 與 \(s\) 中的每顆星星至少有一維座標相同。

有乙個長度為 \(n\) 的星星序列 \(a\) ,請你求出所有奇妙子區間的個數之和。

\(1\leq n\leq 10^5,1\leq k\leq 5\)

解法

首先考慮如何判定序列 \(s\) 是奇妙的,由於 \(k\) 很小我們可以直接使用列舉法。由於每個點都需要被覆蓋,所以我們可以考慮列舉如何解決掉序列 \(s\) 的第乙個點,其實就是列舉 \(p\) 的哪個位置用於解決它,然後往後推看有多少點順帶被解決了,遇到下乙個不能解決的點再列舉 \(p\) 的乙個位置。

不難發現只需要列舉長度為 \(k\) 的所有排列就可以判定合法性,但是暴力判定還是不可行,我們考慮用 \(dp\) 來優化這個過程,由於排列非常小我們可以直接塞狀態裡面。設 \(dp[i][s]\) 表示後 \(i\) 個點用位置排列 \(s\) 的最遠延伸距離(其中 \(s\) 的單個元素被鄧老師形象地稱為錦囊),考慮如何轉移。

寫出轉移需要強大的觀察能力,這裡鄧老師觀察出了問題之間的相似性。我們考慮 \(dp[i][s]\) 和 \(dp[i+1][s']\)(其中 \(s'\) 表示 \(s\) 去掉第乙個錦囊之後的位置排列,設其為 \(x_0\)),只是對於 \(dp[i+1][s']\) 第乙個需要新增錦囊但是可以被 \(x_0\) 解決的位置,是不需要再新增錦囊的。那麼我們可以讓 \(x_0\) 去解決它,所以我們把 \(x_0\) 插入到當前最後乙個錦囊的下乙個位置就得到了 \(i+1\) 的等效子問題,也就是對於以後的影響都等效地傳遞下去了。

實現小細節:\(dp[i][s]\) 開成乙個 \(k\) 維結構體,每一維記錄使用前 \(i\) 個錦囊獲得的最遠延伸距離。

總結

尋找子問題的關鍵:觀察問題之間的相似性。

如果某個元素對於以後的影響是長遠的,但又只能考慮一小步轉移,那麼尋找當前問題的等效子問題,就可以把這個影響傳遞下去,完成轉移。

#include #include #include using namespace std;

const int m = 100005;

int read()

while(c>='0' && c<='9')

return x*f;

}int n,m,cnt,a[m][5],b[m];long long ans=1;

struct node

int hash()

}dp[i&1][cnt]=dp[o][b[t.hash()]];

for(int j=p-1;j;j--)

dp[i&1][cnt][j]=dp[i&1][cnt][j-1];

dp[i&1][cnt][0]=i+1;

mx=max(mx,dp[i&1][cnt][m-1]);

}while(next_permutation(w.p,w.p+m));

ans+=mx-i;

} printf("%lld\n",ans);

}

題目描述

有 \(n\) 棵樹,每棵樹可能是 \(m\) 中之一。小 \(c\) 每天可以選擇連續的一段樹砍掉,要求這一段的長度至少是 \(2\),並且第一棵與最後一棵的種類相同。問有多少種初始局面,使得存在一種方式把樹砍完,答案對 \(10^9+7\) 取模。

\(n\leq 3000,m\leq 10^9\)

解法

首先還是考慮如何判定,顯然的思路是設 \(dp[i]\) 表示砍完前 \(i\) 棵樹是否可行,那麼轉移就列舉 \(1\leq j,當 \(dp[j-1]=1\and a[i]=a[j]\) 都成立的時候 \(dp[i]=1\)

考慮方案的區分其實就是靠 \(a\),所以計數的方法是考慮當前位置可以填上多少個不同的 \(a[i]\),這取決於滿足 \(dp[j-1]=1\) 不同的 \(a[j]\) 數量。

那麼我們嘗試在狀態中記錄這個數量然後 \(dp\),還要保證填入 \(a[i]\) 之後這個數量可以被更新。設 \(dp[i][j][0/1]\) 表示考慮前 \(i\) 個位置,其中有 \(j\) 個不同的滿足條件的 \(a\),\(dp[i]=0/1\) 的不同初始序列總數,我們列舉上乙個狀態 \(dp[i-1][j][k]\),那麼轉移:

\[dp[i][j][1]\leftarrow dp[i-1][j][k]\times j

\]\[dp[i][j+k][0]\leftarrow dp[i-1][j][k]\times(m-j)

\]時間複雜度 \(o(n^2)\)

#include #define int long long

const int m = 3005;

const int mod = 1e9+7;

int read()

while(c>='0' && c<='9')

return x*f;

}int n,m,ans,dp[m][m][2];

void add(int &x,int y)

signed main()

for(int j=0;j<=n;j++)

add(ans,dp[n][j][1]);

printf("%lld\n",ans);

}

2019 2 28 雜題選講

考慮將1至n m分別填入乙個擁有n行m列的 中,不允許重複。你需要滿足以下要求 第i行 1 i n 的最大值為ai。第j列 1 j m 的最大值為bj。請求出合法的填數方案數在模109 7意義下的值。1 n,m 1000 1 ai,bj n m 思路分步 填數 問題符合乘法原理,考慮從大到小填數,先...

雜題選講1 2

把序列排序後 問題轉化為子串行兩兩之間的異或和大於等於k 使用者 trie 樹優化 dp 因為不滿足單調性所以不能用二分來優化 從實際含義入手 ans n 2 sum d1 i dk i sum j k 線性預處理即可 複雜度 o n t 原先做 sa 的題時用過這個套路 列舉長度 len 2 每隔...

9 26雜題選講

非常開心,所有 都咕掉了 cy 簡單計數題,樹狀陣列維護即可。線段樹維護,如果乙個區間整除某個數的時候都等價於減同乙個數,那麼就打上區間減法的標記。複雜度玄學,但是能過。把正著做換成倒著做,把操作變成減去兩邊的數。考慮最大的那個數,顯然在它沒有變化的情況下兩邊的數都不能進行操作,所以如果它沒有變成目...