2024.8.1
T1 集合(mex.cpp)
列舉每個數,求他是\(mex\)的機率,就是取完比他小的,比他大的隨便取的方案數比上總方案數
code
T2 取模(mod.cpp)
有點套路
定義:\(odd\)為奇數,\(even\)為偶數,\(num_{odd}\)或者\(t\)為奇數個數
那個下取整可以變為:
那我們就分成兩部分求:元素和和減了多少個\(1\)
在推正式的式子之前,先看一看對於固定的序列,有結論
簡單解釋:考慮到是不重複的兩兩求和,那麼每個元素都會和其他元素配對\(n-1\)次,然後結合一奇一偶配對會有一個\(-1\),得到式子
接下來推正式的
- 元素和
考慮一個位置的貢獻,當這個位置是\(val\)時,其他位隨便取,\(m^{n-1}\)種序列,貢獻就是一個\(val \times m^{n-1}\),然後\(val \in [1,m]\),共\(n\)位,所以
- 減一數量
假設當前有\(i\)個奇數,那首先分佈有\(C_{n}^{i}\)種,設\([1,m]\)內有\(t\)個奇數,那麼放奇數的位的情況有\(t^i\)種,相應的,偶數位有\((m-t)^{n-i}\)種,結合上面的結論可得貢獻為\(i(n-i)\),故
最後\(ans = ans1 - ans2\)
補上取餘即可
code
T3 魔法(magic.cpp)
暴力給編號連邊+\(bfs\)有\(60\)
正解:根據第二個傳送法,我們可以把顏色相同的放到一起,如果兩個編號間能傳送,其實就是這兩個編號代表的顏色聯通了,可以使用類似並查集的方法合併,使用\(bitset\)實現狀壓,詢問是\(O(1)\)的
小最佳化:假設當前顏色是\(i\),那麼合併到\(i-1\)就完了,因為更小的都已經併入\(i-1\)了
bitset: 一種容器
bitset<N> vis[N];
。其中vis[i][j]表示第\(i\)個bitset的第\(j\)位
code
T4 排位(star.cpp)
貪心最多\(80\)
正解\(dp\),戳它
code
2024.8.3
阿巴阿巴阿巴阿巴阿巴...
T1 怎麼又是先增後減
對於最小的數字,它肯定去兩邊,那麼交換次數就是左/右邊比他大的數的個數,二者取\(\min\),然後從小到大對每個點做一個這個即可
可以使用樹狀陣列最佳化
code
T2 美食節
我們可以採取各種辦法發現某些位置答案一樣,而且構成連續區間
相關理解:
那麼我們每次維護一個答案最優區間,每次和活動區間取交集,如果交集為空,就更新代價和區間
code
T3 環上合併
先說特殊性質
如果序列單增,則每個數都只需要一次操作,但是首尾不同,需要根據當前\(k\)的值討論,具體情況手玩可得
竟然有60
然後我們就關注什麼時候一個數需要一次操作,什麼時候不止一次
為了方便討論,我們新建一個陣列\(b_i = sgn(a_i - k)\)
其中
此時就要把陣列全部染成\(0\)
那麼討論
-
形如\([0,1,1]\)或者\([0,-1,-1]\),此時每個數只需一次操作
-
形如\([0,1,-1]\)或者\([0,-1,1]\),此時必須額外花費一次
再將第二種情況擴充套件一下:\(-1,1\)交替出現時多消耗一次,所以找儘量長的交替段來計算額外答案
code
T4 送快遞
大炮題
定義\(dp_{i,j}\)表示送完前\(i\)件後周欣,青蛙分別在\(a_i,a_j\)時的代價,那我們就根據上一件是誰送的來\(轉移\)
以周欣為例
又因為兩人是等價的,所以把上面兩維交換一下就是青蛙的式子
可得50
正解戳this
這裡關於絕對值,由於只掃一遍,所以不知道內部大小關係,因此兩種情況都要存,故需要兩棵樹,而且維護的時候要把整個含\(i\)的全扔進去
https://img2024.cnblogs.com/blog/1129554/202403/1129554-20240319111911135-280028134.png
2024.8.5
T1
最終態就是前面都為\(1\),後面都為\(0\),那麼挪動總數就是所有\(1\)跑到後面的步數,又稱逆序對數。\(10\)一次減少\(1\),其餘減少\(2\)。
假設值為\(l\),如果\(l\)不是\(3\)的倍數,那麼先手總能使得操作後\(l'\)為\(3\)的倍數,考慮到\(0\)也是三的倍數,所以先手勝(除非一開始就全是\(1\))
同理,\(l\)是三的倍數時,後手勝
code
T2 珂學
每次選擇的最大值肯定不挨著,那麼操作總數就是被選擇的數的總和
那麼就有四種狀態:左/右都/僅一個有(沒有)被選擇的數,程式碼中註釋使用\(X\)表示
合併區間時,如果\(mid,mid +1\)都有被選擇的數,就要分討舍掉哪個數,被舍掉的數所在區間要用舍數後的狀態更新
為了判斷上面的情況,就要記錄對應狀態下左右端點的數是否被選擇(沒有就不管,也不更新)
code
T3 帝國飄搖
貪心,肯定越靠右越好,最劣情況就是第\(k\)大配第\(k\)小,倍增+歸併維護每次擴張的區間,左端點更新為右端點\(+1\)
煩死了都在洛谷上過了怎麼gxyz就是不讓我過之前就有好幾道題都是卡著最後一個點\(TLE\)還死活最佳化不過去把人氣的又耗時間又耗心情真是的cnm老子的正解就TMD不是整潔了啊誰告訴你的我W#%@#
upd on 2024.8.8 : 開O2可過..........
T4 前往大都會
建最短路圖搞大炮+鞋油
2024.8.6
T1 小學奧數題
膜擬了半天出不來,當場似了
T2 BB
定義\(f(u,v)\)表示\(u\)是否支配\(v\),即\(f(u,v) \in \{0,1\}\)
那麼
解釋:賺的錢=從\(B\)那裡收的保護費 - 給\(B\)的保護費 - 買點的花費
考慮到自己的點互相支配不影響賺的錢,所以用類似補\(0\)的操作修改前兩項,然後發現前一項的\(f\)如果為\(1\),\(v\)必然在\(u\)下面,所以\(v\)構成\(u\)的子樹。類似的,第二項的\(v\)都是\(u\)的祖先,構成深度
算出來每個點的\(siz - dep - w\)後排序選擇即可
code
T3 BC
理解大半,直接上馬吧
高消版,也有純大炮的
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int,int> pii;
const int N = 1e3 + 5, M = 50 + 5, Mod = 998244353, inv = 205817851;
//first:機率 second:期望
int n, m, W[M<<1]; pii F[N][M], G[N+M][M];
int Pow ( int x, int y ) { int res = 1; for( ; y; y >>= 1, x = 1LL * x * x % Mod ) if( y&1 ) res = 1LL * res * x % Mod; return res; }
int Inv ( int x ) { return Pow( x, Mod - 2 ); }
int Add ( int x, int y ) { return x + y >= Mod ? x + y - Mod : x + y; }
pii Add ( const pii& a, const pii& b ) {return make_pair( Add( a.first, b.first ), Add( a.second, b.second ) ); }
//加法取餘,比較正常
pii Mul ( const pii& a, const pii& b ) {return make_pair( 1LL * a.first * b.first % Mod, ( 1LL * a.first * b.second + 1LL * b.first * a.second ) % Mod ); }
//Mul:事件A,B期望的合併,E(A+B) = E(A)P(B) + E(B)P(A)
//這個和機率生成函式的導函式(某種情況下好像就是期望,E(x) = F'(1))以及導數的運演算法則有關
//實在不理解可以嘗試使用集合描述法理解
//生成函式詳情看看這個:https://www.cnblogs.com/gtm1514/p/16653405.html
//F[i][j]:同題解含義
//G[i][j]:最終值為(i,i+j)時的答案
//+m是平移座標
void Solve ()
{
cin >> n >> m;
for(int i = -m; i <= m; ++i ) cin >> W[i+m], W[i+m] = 1LL * W[i+m] * inv % Mod;
//簡化高消預處理F,O(nm^2)
//所謂的幾何分佈就是:該情況下期望是1/p或者(1-p)/p,p是機率(但是感覺在這裡沒什麼用)
for(int i = 0; i < n; ++i)
{
pii T[M<<1];//高斯消元係數陣列簡化版,下標含義應當和F的第二維相等
for(int j = -m;j <= m; ++j) T[j + m] = make_pair(0, 0);
for(int j = -m;j <= m; ++j) T[max(-i,j) + m] = Add(T[max(-i,j) + m], make_pair(W[j+m], W[j+m]));
for(int j = -m;j < 0; ++j)
for(int k = 1; k <= m;++k)
T[j + k + m] = Add(T[j + k + m], Mul(T[j+m], F[i+j][k]));
int tmp = Inv((1 - T[0 + m].first + Mod) % Mod);//這個手搓一下樸素高消版本就能知道是啥
for(int j = 1;j <= m;++j) //條件機率
F[i][j].first = 1LL * T[j + m].first * tmp % Mod, F[i][j].second = 1LL * ( T[j + m].second + 1LL * F[i][j].first * T[0 + m].second) % Mod * tmp % Mod;
}
//dp,將<i的答案向>=i轉移
G[0][0 + m] = make_pair(1, 0);
for( int i = 0;i < n; ++i)
for(int j = max(-i,-m);j <= 0;++j)//起點
for(int k = 1;k <= m;++k)//向上“走”了多少步
if(k + j <= 0) G[i][k + j + m] = Add(G[i][k+j+m], Mul(G[i][j+m], F[i+j][k]));//此時用i+j的號打
else G[i+k+j][-(k + j) + m] = Add(G[i+k+j][-k-j+m], Mul(G[i][j+m], F[i+j][k]));//此時用i的號打
int res = 0;
//答案的最終值範圍是[n,n + m]
for( int i = n; i <= n + m; ++i ) for(int j = max(-i,-m); j <= 0; ++j) res = Add(res,G[i][j+m].second );
cout << res << "\n";
}
int main ()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); Solve(); return 0;
}
T4 BD
直接戳吧,部分分,std都有
2024.8.7
困~~~~~
T2 排排
\(P_1 = 1\)啟發我們可以從最值位置考慮,然後就很簡單了,發現只有四種情況
-
\(ans = 0\):原本就單增,判一下即可
-
\(ans = 1\):比較複雜:根據第一個樣例可知\(P_i = i\)的位置可以拿來操作,那麼條件就是左邊沒有右邊下標對應的數,可以用\(\max\)實現
-
\(ans = 2\):\(1,n\)在中間,此時先操作一次可以把一個排到頭頭,然後變成\(ans = 1\)的情況
-
\(ans = 3:\):\(1,n\)在頭頭,但是反的,手算可知三次
code
T1 串串
對於一個點\(i\),如果翻轉後長度超過原串,判一下多出來的長度是否匹配即可
否則看一下新長度到達的點是否可行(倒著掃,因為\(len\)處肯定行),然後判一下多出長度是否匹配即可
code
T4 橋橋
思路很粗暴但不好想到
對操作分塊,\(B\)次後處理,答案轉化為並查集聯通快\(size\),暴力加邊+撤回處理
細節見碼子
T3 序序
戳
2024.8.8
T1 九次九日九重色
上古套路題
手摸樣例配對的\({a,b}\)發現\(a\)按下標(不是值)排序時,\(b\)的下標單增
所以可以預處理所有可能的配對\((i,j)\)(都是下標),然後按\(i\)排序,對\(j\)做一個\(LIS\)
對於\(i\)相同的情況,按\(j\)逆序排序
預處理複雜度\(\sum_{i=1}^n\lfloor \frac{n}{i}\rfloor = n\log n\),\(LIS\)的二分\(DP\)也是這個複雜度
code
T2 天色天歌天籟音
想到莫隊做法了,但是沒想到好的求個數方法,套了個線段樹\(O(n\sqrt n \log n)\)遺憾離場
然後發現想多了
題目要求區間眾數的個數,並不關心是什麼數,所以我們可以開一個陣列\(num_i\)表示出現次數為\(i\)的有多少個
然後維護即可
code
T3 春色春戀春熙風
考慮迴文成立當且僅當最多一個字母的個數是奇數,可以使用異或表示,每一位表示字母個數的奇偶性
那麼\((u,v)\)點對合法就等價於
先說暴力:
對每個可能的狀態(一共\(2^{22}\)種)開桶,從每個節點都搜一次,遍歷時把符合該狀態的點扔進去,並查詢有無互補的點,有的話更新一下長度,平方級別有\(30\)
std:
考慮繼承兒子的答案,那麼為了省事,繼承重兒子答案(因為子樹最大,合併少),對於每個輕兒子暴力走一遍算出路徑,其他資訊都扔掉,陣列留著維護重兒子資訊
還有一個最佳化就是桶裡直接裝最深深度,直接算一下即可
當前樹根\(x\)可能是\(lca\),也可能不是(路徑完全在子樹內),所以要遍歷兒子們更新路徑
click here to see more details
T4 雪色雪花雪餘痕
有兩種方法:直接維護原序列或者維護差分陣列
二者初始都是全為\(0\)
- 維護原序列
有兩種加數方式:在後面一段區間加\(1,2,3..\)或者整體抬升
前者區間長是根號級別,然後可以使用類似揹包的方式轉移
注意有一種情況是前面一部分\(A_i\)遞減,後面增加,這種情況可以從左向右移動最低點,然後左/右就會相應增加/減少相應的根號長區間,動態維護即可
- 維護差分陣列
由於差分陣列還原原序列做的是一個形如\(\sum i\times d_i\)的東西,所以\(dp\)方式有所不同
更多戳這裡吧
2024.8.10
菜
T1 星際旅行
題意等價於:刪掉兩條走一遍的邊後,剩下的是尤拉回路(這樣才能都過第二次)
然後就有:兩個自環,一個自環+一條邊,兩條有公共點的邊三種,累計即可
注意要先判斷圖的聯通,樸素並查集即可
code
T2 砍樹
題目要求最大的\(d\),使得
然後發現二分死了
但是發現\(\lceil \frac{a_i}{d} \rceil\)的取值是根號級的,所以直接暴力列舉可能的除數並儲存
注意,這裡列舉的除數不一定是答案,而是當\(d\)大過一定值時,上取整的值不變,所以存的應是答案\(d\)的等價\(d'\)
然後反帶回去驗證即可
還有一個判斷就是除出來的\(d\)要大於等於選的\(d'\)
code
T3 超級樹
超級抽象
定義\(dp_{i,j}\)表示當前是\(i\)級超級樹,內部同時含有\(j\)條無交點的邊
很抽象,拿樣例來說,\(j = 2\)時,類似\((1),(2-3)\)是符合定義的
然後考慮把兩個\(i\)級超級樹加一個根併成\(i+1\)級來轉移
如果兩棵樹內部路徑分別是\(l,r\)條,那麼不考慮根節點時,就有\(num = dp_{i,l} \times dp_{i,r}\)個方案
然後要討論根節點的去處
-
啥也不幹,\(dp_{i + 1,l + r} += num\)
-
自己獨立作為一個路徑,\(dp_{i + 1,l + r + 1} += num\)
-
連到左/右子樹內的一條路徑上,共\(l + r\)種,又分方向,故有首位之分,\(dp_{i + 1,l + r} += num \times 2(l + r)\)
-
聯通左右樹的一條路,此時總數減一,然後乘法原理+方向可得\(dp_{i + 1,l + r - 1} = num \times l \times r \times 2\)
-
聯通一個子樹內的兩條路,類似的可得\(dp_{i + 1,l + r - 1} = num \times (l(l - 1) + r(r - 1))\)
答案\(ans = dp_{k,1}\)
然後討論迴圈上界,因為裸的上界是2的冪次
如果目標狀態是\(dp_{m,q}\),那麼第二維\(\geqslant m + q + 1\)的狀態肯定毫無意義,那麼考慮到最終狀態是\(dp_{k,1}\),那麼\(l + r\)肯定不超過\(k + 1\),可以拿這點去卡,就能卡成\(k^3\)
code
T4 成績單
啊,1.題讀錯了,暴力寫炸了 2. n 最多50 四次方沒想區間大炮
here here
code
2024.8.12
T1 序列
因為\(q \leqslant 1000\),所以直接預處理\(q\)的整數次冪以協助找最小公比,然後暴力,前兩項確定公比,然後加數就行了,注意\(q = 1\)的情況
code
T3 建造遊樂園
以為是結論,但是是半結論
我們可以直接求尤拉圖數量,然後刪(加)一條邊即為題目所求,共\(C_{n}^{2}\)種方法
考慮容斥
設\(g_i\)表示每個點的度數都是偶數,但圖不一定聯通的數量,\(f_i\)表示答案
對於\(g_i\),構造方法是在\(i - 1\)個點中間任意連邊,然後把度數為奇數的點都連向\(n\),由於度數總和一定是偶數(每個邊貢獻\(2\)),所以這樣是對的。每個邊有連與不連兩種情況,共\(C_{i - 1}^{2}\)條邊,所以
然後要減去不聯通的
不妨把圖劃分成兩部分,第一部分一定聯通,大小為\(j \in [1,i - 1]\),第二部分不一定聯通,大小為\(i - j\),後一部分方案就是\(g_{i-j}\),前一部分就是\(dp_j\),考慮到前一部分聯通大小至少為\(1\),不妨固定一個點進去,剩下\(j - 1\)個點從\(i - 1\)個點中選,則
\(ans = f_n\)
T2 熟練剖分(tree)
大炮,註釋程式碼裡有
code
T4 由乃的 OJ
病嬌一般的題目and時空限制
\(30\)分就是貪心,從高到低,\(\&\)遇\(1\)取\(1\),剩下兩個都是遇\(0\)取\(1\)
std:
首先位運算不滿足交換律,因此運算有順序
然後\(2^{64}\)要開\(ull\)
大致思路就是拆成位,然後為了空間把64個位(64個線段樹)壓成一個\(ull\)拿線段樹維護,初始每一位都是\(0/1\),然後用一堆位運算搞
樹剖的時候要兩個方向
沒過,看看
2024.8.13
T1 那一天我們許下約定
暴力\(30\),然後大炮
設\(dp_{i,j}\)表示前\(i\)天給了\(j\)塊餅乾的方案,雖然\(D\)很大,但真給的天數不超過\(n\),然後就變成\(O(nm)\)的了
答案就是\(dp_{i,n} \times C_{D}^{i}\)
後面那個遞推可搞
code
T2 那一天她離我而去
拆掉\((1,i)\),然後跑\(1 \to i\)的最短路再加上刪掉邊的邊權就是小環,暴力列舉有\(40\)多
然後考慮不把邊刪掉而是連向虛擬點\(n + 1\),具體的,將與\(1\)相連的邊分為連到\(1\)或者連到\(n + 1\),跑一次最短路就行
由於點編號不同,可用位運算分類
ps1:邊的數量最多\(8e4\),直接\(1e5\)得了
ps2:連向\(n + 1\)的邊要在原圖中刪掉
code
T4 戰爭排程
暴力列舉葉子\(20\)
考慮列舉父親狀態然後到葉子時初始化,然後回溯時大炮
設\(dp_{i,j}\)表示以\(i\)為根的子樹的葉子中有\(j\)個人打仗,那麼就是\(dp_{i,k + l} = dp_{ls(i),k} + dp_{rs(i),l}\)
code
T3 哪一天她能重回我身邊
考慮反面向正面連邊,那麼合法的情況就是每個點入度不超過\(1\),翻轉就是改變邊的方向,形成若干聯通塊
根據抽屜原理,邊數 \(>\) 點數時一定有一個點入度為\(2\),一定不合法,那麼剩下的就是樹或基環樹,每個塊內大炮求翻轉次數最後彙總即可
click to get more details
2024.8.14
4道T4,吃滿暴力就能上三位數
T1 2-Coloring
上來一道紫
暴力:\(30pts\),狀壓列舉每一行的狀態check即可
思路難泵,戳這裡看第一篇,講的清楚
code
T2 連通塊
暴力:\(60pts\),每次搜整個塊即可
trick:刪邊改為加邊,就是初始時把標記的未刪的邊合併,然後離線倒序跑詢問,用並查集維護樹的直徑
答案就是查詢點到塊內直徑其中一端的距離
code
T3 軍隊
暴力:\(20pts\),模擬,上限在於陣列大小和\(c\)的限制
重疊矩形使用掃描線,可以\(log\)處理出每行多少雌的,然後設\(x\)表示雌雄數量中較小者,然後它和\(\lfloor \frac{y}{2} \rfloor\)的大小關係不同時有不同的計算式子,可以使用字首和最佳化成\(O(1)\)
code
T4 棋盤
暴力:\(0pts\),寬搜爆完,但聽說大炮有\(30\)
奇怪的維護,戳
2024.8.15
T1 Kanon
\(40pts\):開兩個變數記錄向左/右最遠跑了多少,如果一個球當前位置超過原位置+最遠距離就可能產生貢獻,說可能是因為當前位置可能越過上一個球的歷史位置,此時沒貢獻
考的時候想成一堆球打架就不會維護了qwq
code
\(100pts\)
每個雪球大小來源都是連續區間,沒有交集那麼答案就是區間長,有的話要判斷交集屬於哪個球,然後可以二分找到\(t\),使得第\(t\)天無交集,第\(t + 1\)天有交集,則可得知交集是誰的
球之間的雪最需要判斷主權,兩端以外沒必要(肯定是第一個和最後一個)
T2 Summer Pockets
講解見the first one
code
T3 空之境界
裸區間大炮可以\(60pts\)
然後考慮轉化:二分列舉答案,做\(01dp\),表示區間內是否存在小於等於二分值的數,這樣就能用bitset最佳化
然後將區間大炮的轉移方式小改一下,就有兩種情況:
-
更新\([i,j]\),如果\([i + 1,j - 1]\)符合並且\(cost_{i,j}\)也符合條件,我們就能認定\([i,j]\)可行
-
用\([i,j]\)擴充套件,這一步有點像列舉斷點更新,即如果\([i,j]\)符合條件,那麼\([i,k]\)的狀態(就是\([i,j]\)以後區間的狀態)可以使用\([j + 1,k]\)更新
最後檢查\([1,n]\)是否為\(1\)就行了
code
T4 穗/P4690 Ynoi2016
\(20\)的模擬 +\(20\)的普通莫隊 + \(40\)的帶修莫隊
剩下\(20\)全踏馬是珂技
2024.8.17
考場暴力剛好\(100\)
T1 Set
考場以為子集不連,直接亂搞起步睡到\(50\)
正解很簡單:餘數共\(n\)種,但字首和\(s_0 \sim s_n\)一共\(n + 1\)個,所以找到相同的輸出區間即可。。。
好短。。。
T2 Read
\(x\)本書可以“消”掉\(x + 1\)本書
那麼如果有書的數量\(\geqslant \frac{n + 1}{2}\),就說明有書會剩下,反之答案為\(0\)
考慮到\(a\)開不下,所以記一個\(val\)和一個\(sum\),\(sum\)為\(0\)時\(val = a_i\),然後根據是否和\(val\)相同對\(sum\)加一減一,然後再生成一遍\(a\)記錄\(val\)個數,如果滿足有剩餘的條件,答案就是\(x - (n - x + 1)\)
code
T3 題目交流通道
亂搞\(30\)
然後如果有\(d_{i,j} = d_{i,k} + d{k,j}\),那麼\(d_{i,j}\)的長度範圍就是\([d_{i,j},k]\)共\(k - d_{i,j} + 1\)種,乘起來有\(60\)
考慮\(d_{i,j} = 0\)的情況,此時把\(0\)邊連起來的點縮成一個(圖論中曰為“團”),然後分團內和團外進行容斥,團內情況類似之前尤拉圖構造的情況,式子也很像,然後團外(團與團之間,共\(siz_1 \times siz_2\)條邊)的話還是找符合上面條件的\(d_{i,j}\),如果有,那麼之間的邊隨意,如果沒有,那麼至少一條長為\(d_{i,j}\),也可容斥得出
code
T4 題目難度提升
構造
如果序列中間有數字出現兩次以上,就一直讓他作中位數,然後一小一大往裡加即可
然後考慮一般情況
首先有結論:當前未填數的最小值必須大於等於當前中位數
那麼就要看中位數情況,分加之前有奇數個/偶數個數字討論
如果序列內沒重複數字,那就走流程
如果有重複的,分析重複數字的位置,考慮在一定情況下讓重複數字成為中位數
更多戳這裡
code
附加:消除遊戲
不會
2024.8.19
T1 電壓
暴力拆邊+check有\(25\)
然後要求刪邊後是二分圖,那麼刪的邊都在奇環上,考慮\(dfs\)生成樹+返祖邊check+差分搞
gxyz第一男神wmw題解
code
T3 奇蹟樹
一眼樹的直徑,想從某一端點出發搜完整棵樹完成賦值
裸搜,假的,\(12pts\)
假了的原因在於不能保證其他點和作為終點的端點關係合法
處理很簡單,先把不在直徑上的點遍歷完再給直徑上的點賦值,很容易證明這樣最優(考慮回溯,在直徑上回溯然後跑到別的點肯定垃圾)
code
T2 農民
預設\(1\)為根全死了
修改後的暴力高達\(80\)
std:考慮維護每個點能吸收的肥料值的範圍,一個節點會把\([l,r]\)分成\([l,w_u)\)和\((w_u,r]\),然後一個點吸收範圍就是祖先吸收範圍的交集,使用線段樹維護即可
code
T4 相逢是問候
click
2024.8.20
又雙困了一上午╯﹏╰....
T1 博弈
先手必勝:至少一個數個數為奇數
奇偶性使用異或表示,但考慮到\(3 \oplus 2 \oplus 1 = 1\),所以要先\(hash\),然後考慮容斥,狀態相等的點之間不合法,減去即可
code
T3 大陸
做過的原題,這裡有
T2 跳躍
考慮到最優肯定是在某些區間裡反覆橫跳,設\(l_i\)表示以\(i\)為右端點,和最大時的左端點
那麼就是在\([l_{i_1},{i_1}],[l_{i_2},{i_2}]...\)的區間裡跳
為了維護跨區間的跳躍,分別維護從\(1\)跳到\(i\)所需的最小步數和此時對應的分數,不足\(k\)的部分在\([l_i,i]\)內反覆橫跳,然後列舉上一個橫跳區間,算出從那裡跳過來時需要的步數以及對應分,考慮到方向問題,要奇偶判斷一下,然後掃一遍就行
code
T4 排列
暴力\(40\)
剩下平衡樹,不會
2024.8.21
Fate
看到教堂自動浮現名場面
暴力\(only\) \(19pts\)
大炮,設\(f_i,g_i\)表示從\(s\)到\(i\)的最短路徑,最短+1路徑的條數,\(dijkstra\)預處理dis
記搜轉移即可
code
T2 EVA
睡了\(v\)相同的部分
考慮到以魚的座標為網的一端一定不劣,所以列舉魚作為參考系,其他魚根據相對運動可以算出進入網的時間範圍,由於是\(double\)型別所以離散化一下,然後區間差分找使\(\sum w\)最大的時間點即可
code
T3 嘉然登場
狀壓\(40\) + \(K = 1\)的\(20\) \(= 60\);
考慮根據\(a_i\)的大小和與\(\frac{k}{2}\)的差的絕對值為排列依據降序排列,前面一部分抽象為\(1\),後面抽象為\(0\),和\(K = 1\)的情況類似,詳細證明戳這裡
code
T4 Clannad
爆了
題目要求包含區間內所有關鍵點的最小聯通子樹
有結論:
將關鍵點按\(dfn\)序排序後,邊數 \(=\) \(\huge\frac{\sum\limits _{i = 1}^{k- 1}dis(a_i,a_{i+1}) + dis(a_k,a_1)}{2}\),點數\(=\)邊數\(+1\)
可結合\(dfs\)順序理解
依此暴力\(40\)
然後可以使用回滾莫隊(只刪不加) + 連結串列(刪除\(O(1)\))維護,檢查祖先的\(log\)使用\(dfn\)序\(——ST\)表最佳化成\(O(1)\),\(O(n\sqrt n)\)然後再小卡一下(__lg
和交換\(ST\)兩維)
code
2024.8.22
今天題難,才爆出來\(60\)多
對應的講解戳題可得
或者這個
T1Skip
暴力:\(30pts\)
這個程式碼用魔法常數可得\(60\)
T2String
code
T3Permutation
暴力大炮:
code
std:
code
T4小P的生成樹
參考這個嚴謹一點
code
2024.9.8
大數學時代
T1 喜劇的迷人之處在於
首先找出使\(ax\)為平方數的最小\(x\),分解質因數即可實現,然後二分找一個平方數\(pf\)使得\(x \times pf\)在範圍內即可
後面三道就亂殺人了
戳戳
T2 鏡中的野獸
本質是容斥,但是樸素版本會算死人的,所以開科技(莫反)
code
T3 我願相信由你所描述的童話
正反兩遍平方級大炮跑最長子序列類似的板子然後沒去重死了
重複原因就是統計答案時在列舉坡度轉折點\(t\),如果中間是平的就\(gg\)了
T4 Baby Doll
一眼頂針鑑定為神秘外星禁忌知識根本不可做
2024.9.15
我是盲人
T1 出了個大陰間題(repair
瞎 * 1,看成自由合併,然後被求\(b\)難倒,事後才發現每次的\(b\)都是\(2^{k - 1} - 1\)...
部分分(80pts):
定義\(dp_{i,S}\)表示當前最大值為\(i\),合併狀態為\(S\)的代價和,\(i\)的範圍最大到\(\max(a_i) + n \leqslant 2n\),然後模擬就行
考慮到題目說的是排列,而狀態只能表示選沒選,所以還得另開一個存方案數
std:
可以預處理每個狀態下的最大\(a\),然後實際合併到此狀態的\(a'\)無非就是相等或差\(1\),所以上面\(dp\)的的第一位直接改成\(2\)表示對應情況,其他沒什麼改變
code
T3 是我的你不要搶(string)
瞎 * 2,看成\(S\)尾部的倒序了...
想到自動機的fail可以搞,但是好像要撤銷,不會了
後邊發現hash+記錄答案可過...
至於原理,考慮最多隻有\(n^2\)種不同詢問,\(n^2 > Q\)的話就是\(Q\),複雜度\(O(\frac{Q\sum len}{n})\),反之複雜度就是\(O(Q\sum len)\),兩種都是\(O(\sum len \sqrt{Q})\)級別的,可過
然後\(map\)會被卡\(T\),純\(ull\)會卡\(WA\),對應用\(un_map\)和取餘再雜湊解決即可
code
T2最簡單辣快來做(satellite
瞎 * 3,沒看到\(ans\)沒清空暴力似了
絕對值拆成四個方向的矩形維護
對於每個衛星相對查詢點所在的四個矩形哪一個的序列,只有\(O(n^2)\)種可能 的情況。 也就是對於衛星\((x_i,y_i)\)用直線\(x = x_i\)和\(y = y_i\)將平面分割成\(O(n^2)\)個格子。 如果查詢點落在直線上,根據絕對值性質直接選擇任意一個相鄰的矩形。 如果落在格子裡,就直接選擇對應的矩形。 類似之前的二維字首和,在直線的每一個交點處求出四個方向矩形的和。 在查詢的時候,透過先前的離散化找到對應的格子,然後利用O(log v) 快速冪(實測88pts),或者是分塊預處理的O(1)光速冪,計算出查詢點到格子四個角的額外貢獻
code
T4 顯然也是我整的
好像是每次找到一些單獨成塊的點(這裡的點可能是單點,也可能是縮完的點)計入答案,然後構造 + 遞迴搞
具體還是不太清楚
2024.9.16
重新定義飲料為一大杯冰沙
胃:這把生死局(指抿一口就開始起反應...)
早上就不停反嘔,下午整這一出真是笑嘻了
T1 不相鄰集合
以為貪心假的,結果對了
就是對新加的數看看有沒有左鄰右舍被取過,沒有就計入答案
code
T2 線段樹
暴力\(20\)
考慮到線段樹開點方式,點編號之和肯定可以寫成一次函式,具體的,設\(f_{n,x}\)表示根為\(x\),有\(n\)個葉子是的和,那麼\(f_{n,x} = k_n \times x + b_n\)
然後有關係
代入表示式可得:
可以記憶化處理
然後正常跑查詢,如果找到\([l,r]\)在詢問區間內,貢獻就是\(k_{r - l + 1} \times id + b_{r - l + 1}\)
byd mid沒開ll耗掉不少時間,被#define int long long教育力
code
T4 園藝
聽說資料很水最多列舉兩個拐點可過..
正解鞋油+單隊,感覺和之前掉餡餅的題很像
std1
std2
2024.9.22
菜死了
T1 自然數
下洗了,不會
先求出\([1,i]\)的mex,記為\(mex_i\),這個陣列單調不降。然後記錄\(a_i\)在後面第一次出現的位置\(nxt_i\)
接下來列舉左端點,每次移動都為刪掉一個\(x = a_l\),然後\(mex\)中大於\(x\)的值就會被改成\(x\),修改區間右端點就是\(nxt_l - 1\),左端點需要二分找第一個大於\(x\)的點,可以透過記錄最大值實現
然後上線段樹做區間修改,區間最值,區間求和即可
code
T2 錢倉
手膜膜錯辣
改過來後發現就是貪心,然後存在這樣一個點:該點後面的點的貨物不會運到該點前面
這個點滿足是最大子段和的起點(意思就是有足夠多的貨補給後面),由此處破環成鏈貪心即可
code
T3 遊戲
考場上拿無窮近似推了個賊像的式子,然而還是遺憾離場
std
code
T4 暴雨
暴力搜尋\(20\)
正解大炮,???
2024.9.28
T1 一般圖最小匹配
貪心可以有\(75\),但是考場上\(RE\)了一半多,後來使用魔法常數就\(OK\)了
damn
整潔大炮
先對\(a\)【排序,這樣後取相鄰的一定最優
定義\(dp_{i,j,0/1}\)表示到第\(i\)個數匹配了\(j\)對,並且第\(i\)個數沒有用上
則
使用滾動最佳化
code
T2 重定向
暴力列舉刪除位+填數有一半分
考慮到字典序最小,使用貪心
設\(minnum\)表示最小的未填數,\(minn_i\)表示\(a_i \sim a_n\)中最小的數
-
\(a_i = 0\)
如果minn_i < minnum,就要把\(minn_i\)刪掉往這裡放
-
\(a_i \neq 0\)
- \(a_i > a_{i + 1}\),則刪掉\(a_i\)更優
- \(a_{i + 1} = 0\),如果\(a_i > minnum\),那麼刪掉\(a_i\)更優
可以用優先佇列維護要填的數
- 注:在初始化優先佇列中,迴圈上界為\(n\)時會\(RE\),要改為\(n + 1\)(
不知道為甚莫)
code
T3 斯坦納樹
戳
T4 直徑
再戳
2024.10.2
障保齡之東去,挽暴力於既倒
T2 肥胖
忘了可以從\(1\)走到其他點開吃,直接成\(10\)分,還都是\(-1\)...
為了成功,肯定想要把限制放大點
於是可以建最大生成樹
然後考慮選擇的邊中最小的,設為\((u,v,w)\),此時有一個結論:先吃完一個子樹再去吃另一個不劣於反覆橫跳
證明的話,考慮反覆橫跳吃的某一步肯定是吃了一棵子樹的最後一個然後跳到另一個,此時經過\((u,v,w)\)時的寬既有一棵子樹的所有糖還有另一棵子樹的一些糖,那還不如全吃完一棵,然後只經過一次\((u,v,w)\)到另一棵樹裡吃吃吃
然後考慮答案,設\(sum_u\)表示\(u\)字數內糖果總和,\(ans_u\)表示吃完\(u\)為根的子樹的最大初始體寬
假設從以\(u\)為根到以\(v\)為根,此時一個是要保證能過邊,即\(w \geqslant sum_u\),一個是要能吃完\(v\)樹,就是\(ans_v \geqslant sum_u\),兩答案取\(\min\),反之同理,\(u,v\)互換即可,最後兩個\(min\)取個\(max\)即可
注:由於一開始\(ans_i\)未求出,所以初始化成極大值
code