7 13 ACM 部分簡要題解

2022-05-11 11:26:36 字數 3801 閱讀 1519

有乙個音遊,給出你每個鍵的掉落順序和價值,你可以用左手或右手去點選鍵位並獲得價值,並給出四個規則:1、左手不能連用;2、左手交叉到右手右邊的價值會乘上 \(p1\%\);3、右手交叉到左手左邊的價值會乘上 \(p2\%\);4、右手連用的價值會乘上 \(p3\%\)。你還可以放棄一些鍵不去點選。問最大價值是多少。

根據題意,左手和右手分別所處位置對答案無影響,只有它們的相對位置對答案有影響,所以我們不會連續放棄超過乙個鍵

顯然可以用 \(dp\) 去解決這個問題。記 \(f_\) 表示第 \(i\) 個鍵我們用左手點選的價值,\(g_\) 表示第 \(i\) 個鍵我們用右手點選的價值,那麼轉移方程就很容易得出了(注意不要忘了某些情況),最終答案就是 \(max\,g_\}\)。

int n,s[n],t[n],p1,p2,p3,f[n],g[n];

signed main()

printf("%lld\n",max(f[n],g[n]));

return 0;

}

問 \(n\) 條直線最多能組成多少同旁內角。

1、三條直線最多組成 \(6\) 對同旁內角,使得 \(n\) 條直線中每三條直線都能組成 \(6\) 對同旁內角,答案即為 \(6c_^\)。

2、筆算一下,直接 oeis

給出 \(m\) 個區間和 \(n\) 組詢問,每組詢問給出 \(k\) 個點 \(a_\),求在區間 \([l_,r_]\) 中的所有點排序後,\(r_-l_+\sum i\times a_\) 的最大值,此處 \(a_\) 表示在該區間中的點已被從小到大排序。(本題中 \(n\) 與 \(m\) 同階)

首先有個重要的結論:如果乙個區間被另乙個區間所包含,那麼這個區間一定不會被選到。於是我們可以把所有被其他區間完全包含的區間去掉,並且把剩下的區間按左端點排序,這樣就可以得到左右端點都嚴格遞增的區間集合。

考慮把對於每組資料讀入的 \(k\) 個點從小到大排序,這樣就得到了乙個數值串行。考慮選取一些連續的數,有多少區間能夠覆蓋全部這些數。我們可以記對於每個數值,最左邊覆蓋它的區間為 \(ql_\),最右邊覆蓋它的區間為 \(qr_\),則有區間能夠覆蓋一段連續的數值串行 \([l,r]\) 的條件就是 \(ql_\geq qr_\)。現在考慮求出 \(ql_\) 和 \(qr_\)。

由於一開始的結論,所以我們可以對於每個 \(a_\),二分出不在 \(a_\) 右側的最大的 \(l_\) 和 不在 \(a_\) 左側的最小的 \(r_\)。當然,如果找不到這個 \(l\) 或 \(r\),或者是找到了卻沒覆蓋到這個點,那麼可以記這個位置 \(ql_=ql_=-1\)。

暴力去列舉數值串行的每個 \([l,r]\) 顯然會超時,考慮優化。發現當我們固定左端點 \(l\) 時,如果 \([l,r]\) 可以被區間所包含,則 \([l,r-1]\) 也可以被區間所包含。所以我們可以對於每個 \(l\) 去二分 \(r\) 並找到最大值。查詢若干個連續區間集合的 \(r_-l_\) 的最大值可以用線段樹或 \(st\) 表。這樣的做法是 \(o(nlog^n)\) 的,如果優化其中一些地方也可以做到 \(o(nlogn)\)。

這題可以固定左端點二分右端點,於是我們再考慮可不可以用雙指標去解決它。考慮把右指標 \(r\) 一直向右移,直到不滿足 \(ql_>=qr_\) 或出現 \(ql_==-1\) 或 \(r\) 大於 \(m\)(此時 \(m\) 為已經預處理過後剩下的區間總數)為止,然後可以求出 \([l,r-1]\) 這段數值串行的價值。然後再把左端點向右移,直到重新滿足 \(ql_>=qr_\) 為止。然後去掉了一堆小錯誤之後 「愉快」 wa on test 43。

經過了漫長的尋找 \(hack\) 資料之後,終於由 \(kqh\) 貢獻了一組 \(hack\) 資料如下:

1 2

1 100 3 10000

4 1 4 5 10001

1 31 100 3 10000 9999 10002

4 1 4 5 10001

將上做法帶入這組資料就會發現出了大問題。原因是當我們到 \(10001\) 這個數發現不滿足與左端點被某一區間所覆蓋時,我們就會把左端點一直右移到與這個右端點滿足條件為止。這樣就會忽略掉在 \(l\) 右移過程中 \([l,r-1]\) 可能作為一種更優答案的情況。(該資料的可以在 \(kqh\) 的 題解 中觀察)於是我們可以在左端點右移的過程中一直計算 \([l,r-1]\) 這段數值串行的最大答案即可。

#include #define ri register

#define int long long

using namespace std; const int n=400010;

inline int read()

while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch-'0'), ch=getchar(); return s*w;

}int n,m,book[n],a[n],qz[n];

struct edgee[n];

inline bool cp(edge x,edge y)

void build(int x,int l,int r)

build(lc,l,mid), build(rc,mid+1,r);

push_up(x);

}int ask(int u,int v,int l,int r,int x)

struct point q[n];

signed main()

int cntt=0;

for(ri int i=1;i<=m;i++) if(!e[i].fg) e[++cntt]=e[i]; m=cntt;

int fir=0;

for(ri int i=1;i<=m;i++) fir=max(fir,e[i].r-e[i].l);

build(1,1,m);

for(ri int t=1;t<=n;t++)

if(res==-1 || e[res].r=a[i]) res=mid, r=mid-1;

else l=mid+1;

}if(res==-1 || e[res].l>a[i]) q[i].ll=q[i].rr=-1;

else q[i].rr=res;

} int ql,qr; ql=qr=1; int now=0;

for(ri int i=1;i<=ki;i++) swap(q[i].ll,q[i].rr);

while(ql<=ki && qr<=ki)

while(qr<=ki && q[ql].rr>=q[qr].ll&& q[qr].ll != -1) now+=(qr-ql+1)*a[qr], qr++;

ans=max(ans,ask(q[qr-1].ll,q[ql].rr,1,m,1)+now);

if(q[qr].ll == -1 || q[qr].rr==-1 )

else

while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar(); return s*w;

}double n,p,res,g; unordered_mapq;

struct edgee[n];

signed main()

clock_t tb=clock(),lm=clock();

while(((double)tb)/clocks_per_sec < 0.95-((double)lm)/clocks_per_sec)

tb=clock();

} puts("impossible");

return 0;

}

20191029校內ACM部分題解

給定乙個在 0,1 等概率隨機區間的隨機變數 x 給定 k 求下面的式子對998244353取模的值 k le 10 6 lim sum n x i bar k 之後發現這個東西就是在讓我們求隨機變數 x 與他期望的值的 k 次方的期望 那麼我們轉化成下面等價的式子 e x e x k 首先.我們把...

NOIP2018 簡要題解(部分)

目錄 noip2018 簡要題解 部分 pj t1 標題統計 t2 龍虎鬥 t3 擺渡車 t4 對稱二叉樹 tg day1 t1 鋪設道路 t2 貨幣系統 t3 賽道修建 day2 t1 旅行 t2 填數遊戲 t3 保衛王國 入門難度 includeusing namespace std int m...

AGC044 簡要題解(部分)

乍一看資料範圍非常唬人,但是仔細思考一下就可以發現這樣乙個事實 從 x 逆著執行操作回到 0 的時候,除了最後一次連續執行若干次 1 操作直至 0 之外,其餘的時候,每兩次除法之間,用 pm1 造成的增量只會在 2,2 之間。實際上,如果下一次除數是 2 或 3 那麼增量只會在 1,1 之間。證明只...