百度之星2018初賽A輪

2021-08-22 18:18:50 字數 3905 閱讀 8588

題目描述

題解

簽到題。

排個序列舉小的兩條然後二分出第三條就好了。

其實排序之後只要看連續的三條就行了。

**

#include

#define n 1005

using

namespace

std;

int n,s[n],ans;

int main()

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

} return

0;}

題解

當時腦子抽了寫了個平衡樹艹過去的。

其實用雙向鍊錶搞搞判判就好了。

貼的是平衡樹的**。

**

#include

#define ll long long

#define n 400010

using namespace std;

int n,q,cnt,rt[n],l=2147483647;

struct node

void clear()

}t[n*10];

inline int get()

class functional_trape

void split(int

x,int &a,int &b,int k)

pushdown(x);

if(t[t[x].lc].size>=k)

else

} int merge(int a,int b)

else

return

x; }

void insert(int &x,int w,int val)

void erase(int &x,int w)

void reverse(int

x)

int qry(int

x,int w)

return t[x].x;

} bool empty(int

x)}t;

int main()

if(tp==2)

printf("%d\n",t.qry(rt[u],w));

t.erase(rt[u],w);

}if(tp==3)

}} return

0;}

題解

我們肯定會把若干段1剪開放在字首。

一段1被剪開的代價是2(除非是開頭的1或結尾的1)。

注意到每次操作最後可以有一段1不剪右邊,放在1和0的分界點。記這種情況為特殊情況

所以定義f[i]表示剪i次,沒有特殊情況的最長字首。

g[i]表示剪i次,有特殊情況的最長字首。注意特殊情況只能出現一次。

然後轉移一波就好了。

**

#include

#define n 10005

using

namespace

std;

int n,k,tot,len,ans,s[n],f[n],g[n],flag,tag;

int main()

if(len)s[++tot]=len,flag=1;

int st=1;

if(tag)g[0]=s[1],st=2;

for(int i=st;i<=tot;i++)

else

g[j]=max(g[j],f[j-1]+s[i]);}}

}for(int i=0;i<=k;i++)ans=max(ans,max(f[i],g[i]));

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

} return

0;}

題解

一開始以為是兩排,一排n個座位,想了好久不會做。

後來發現是一排,總共2*n個座位,然後就會做了。

答案乘了個階乘,所以求期望實際上是求方案數。

定義狀態f[i][j]表示前i對情侶,有j對連在一起的方案數。

轉移,考慮新加一對情侶對之前的影響。

新加一對情侶,可能增加一對相鄰的情侶,或不變,或減少一對,或減少兩對。

具體的轉移式見**。

這個題要先把dp離線算出來再做,不然會超時。

**

#include

#define mod 998244353

#define ll long long

#define n 1005

using namespace std;

int n,m;ll f[n][n],ans;

int main()

while(~scanf("%d%d",&n,&m))

return 0;

}

當時就過了這四題,然後就跑了。

題解

題目說的是每次讓乙個點失效,我們逆向思維,考慮每次讓乙個點生效。

這題關鍵就是這個逆向思維了。

然後每次生效乙個點,我們就把它和它的左邊右邊合併。

合併的時候可以用啟發式合併,這樣就是log方的了。

至於區間和的計算,區間 [i,j] 和等價於 sum1[j]-sum[i-1],或 sum2[i]-sum2[j-1]。

所以對於每段,維護一下sum[i],在啟發式合併的時候再另一邊二分找的最近點就好了。

**

#include

#define inf 999999999999999999ll

#define iter multiset::iterator

#define ll long long

#define n 100010

using namespace std;

int n,k,fa[n],s[n],p[n],flag[n];

ll sum1[n],sum2[n],ans[n],res;

multisett1[n],t2[n],t3[n],t4[n];

int find(int

x)void merge(int

x,int

y) }

else

swap(x,y);

} fa[x]=y;

for(iter it=t1[x].begin();it!=t1[x].end();++it)

t1[y].insert(*it);

for(iter it=t2[x].begin();it!=t2[x].end();++it)

t2[y].insert(*it);

for(iter it=t3[x].begin();it!=t3[x].end();++it)

t3[y].insert(*it);

for(iter it=t4[x].begin();it!=t4[x].end();++it)

t4[y].insert(*it);

t1[x].clear();t2[x].clear();

t3[x].clear();t4[x].clear();

}int main()

for(int i=n;i;i--)

for(int i=1;i<=n;i++)scanf("%d",&p[i]);

for(int i=n;i;i--)

for(int i=1;i<=n;i++)printf("%i64d\n",ans[i]);

} return

0;}

2018百度之星初賽1003

problem description 度度熊有一張紙條和一把剪刀。紙條上依次寫著 n 個數字,數字只可能是 0 或者 1。度度熊想在紙條上剪 k 刀 每一刀只能剪在數字和數字之間 這樣就形成了 k 1 段。他再把這 k 1 段按一定的順序重新拼起來。不同的剪和接的方案,可能會得到不同的結果。度度熊...

2018百度之星初賽B輪部分題題解

由於昨天那場和牛客多校衝突了,就沒打a輪。聽說昨天題還很難。而今天題目難度著實跨度太大,前三題都屬於簽到題,稍微想一想都能做出來。但後面的題,怕是神仙題了。弱弱的我用了1個半小時才a完3題,自然是滾粗複賽了。下面看一下這幾道題 1001 degree hdu6380 剛開始看這道題,思路其實並不是特...

2018百度之星初賽 A 1002

度度熊正在學習雙端佇列,他對其翻轉和合併產生了很大的興趣。初始時有 n 個空的雙端佇列 編號為 1 到 n 你要支援度度熊的 q 次操作。1 u w val 在編號為 u 的佇列裡加入乙個權值為 val 的元素。w 0 表示加在最前面,w 1 表示加在最後面 2 u w 詢問編號為 u 的佇列裡的某...