Wannafly模擬賽4 題解

2021-08-10 13:20:49 字數 4012 閱讀 7842

a:

fst是一名可憐的小朋友,他很強,但是經常fst,所以rating一直低迷。

但是重點在於,他非常適合acm!並在最近的區域賽中獲得了不錯的成績。

拿到獎金後fst決定買一台新筆記本,但是fst發現,在**能承受的範圍內,筆記本的記憶體和速度是不可兼得的。

可是,有一些筆記本是被另外一些「完虐」的,也就是記憶體和速度都不高於另外某乙個筆記本,現在fst想統計一下有多少筆記本被「完虐」。

解法:很老的題了,一維排序,二維bit,不過要離散化一發。

#include using namespace std;

const int maxn = 100010;

int n, ans=0, c[maxn];

typedef pairpii;

pii node[maxn];

vector v;

int getid(int x)

int lowbit(int x)

void update(int x)

return ret;

}int main()

return 0*printf("%d\n",ans);

}

b:fst作為小朋友,經常會遇到和距離有關的問題,但是他已經厭倦了曼哈頓距離和歐幾里德距離,所以fst就定義了一種fst距離。

這種距離並不用於空間或平面中,而運用於fst發明的一些神奇的演算法中(唔... ...)。

設i號元素的特徵值為ai,則i和j的fst距離是 |i2 - j2|+|ai

2 - aj

2|。為了實現某新的資料結構,fst想在一大堆元素中找出距離最大的一對元素,他不關心是哪一對元素,只想求出最大距離。

解法:假設i>j,因為(i,j哪個大不影響),然後對於a【i】和a【j】討論一下,就可以知道維護i*i+a[i]*a[i]和i*i-a[i]*a[i]就好了。

#include using namespace std;

const int maxn = 1e5+10;

typedef long long ll;

int n;

ll a[maxn], mx1[maxn], mx2[maxn];

int main()

c:考慮維護乙個這樣的問題:

(1) 給出乙個陣列a,標號為1~n

(2) 修改陣列中的乙個位置。

(3) 詢問區間[l,r]中所有子集的位運算and之和mod(109+7)。

位運算and即為「pascal中的and」和「c/c++中的&」

我們定義集合s=

若集合t,t ∩ s = t,則稱t為s的子集

設f(t)=at1 and at2 and ... and atk  (設k為t集大小,若k=0則f(t)=0) 

所有子集的位運算and之和即為∑f(t)

那麼,現在問題來了。

解法:仔細想一想就知道&運算只要有乙個0,這個子集這個位的貢獻就是0,所以只要統計,一段區間中這個位的1的個數就可以了。

#include using namespace std;

const int maxn = 2e5+10;

typedef long long ll;

const ll mod = 1e9+7;

struct nodetree[maxn*4];

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

return;

}int mid=(l+r)/2;

build(l,mid,rt*2);

build(mid+1,r,rt*2+1);

for(int i=0; i<=32; i++) tree[rt].a[i]=tree[rt*2].a[i]+tree[rt*2+1].a[i];

}void update(int pos, int val, int l, int r, int rt)

return;

}int mid=(l+r)/2;

if(pos<=mid) update(pos,val,l,mid,rt*2);

else update(pos,val,mid+1,r,rt*2+1);

for(int i=0; i<=32; i++) tree[rt].a[i]=tree[rt*2].a[i]+tree[rt*2+1].a[i];

}node query(int l,int r,int l,int r,int rt)

ll b[maxn];

int main()node[maxn*4];

int sz;

void init()

}return 13;

}}tree;

char s[maxn];

int main()

else

}}int main()

n%=mi[i];

}ans += num[0][tmp];

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

}return 0;

}

f:fst的腦洞非常大,經常幻想出一些奇怪的東西。

某一天,fst幻想出了一棵沒有邊際的二叉樹,腦補著在那棵二叉樹上行走的場景。

fst一開始在二叉樹的根,然後fst寫下了乙個由『l』『r』兩種種字元構成的串,他稱這個串為初始串,按照這個串的順序,碰到乙個『l』就移動到左兒子,碰到乙個『r』就移動到右兒子。fst最後的位置就是他的起點。

然後fst有寫下乙個串,他稱這個串為操作串,由『u』『l』『r』三種字元構成,『u』表示移動到當前點的父親(特殊地,我們定義根節點的父親為根自己),『l』『r』同上。

但是fst覺得直接按照操作串一步一步走十分無聊,所以fst會跳過一些操作(心情不好的時候也可能跳過所有操作,或不跳過),現在fst想知道他會走到多少種可能的終點。

由於答案可能很大,所以只需輸出答案mod (109+7)的值。

解法:演算法一: 構樹 30%

我們可以用某種方式把樹構出來,然後枚舉子序列在樹上遍歷。

表示出來的樹的大小不會超過 220

。演算法二: 構一部分樹 50%

因為在樹上遍歷的範圍只和操作串有關,所以構樹時深度只要保留 10 層就行了。

演算法三: 特殊點討論 70%

操作沒有 u,也就是只會往下走,那麼我們可以 dp

狀態有 4 種,沒有去過左兒子的點的個數,沒有去過右兒子的點的個數,左右兒

子都沒去過的點的個數,左右兒子都去過的點的個數。

轉移根據這個狀態定義應該顯然。

演算法四: 100%

對於 u 操作,我們只需做一些小修改。

因為 lr操作會和 u 操作抵消,所以我們的實際操作時的使用序列一定是這樣的:

uu…uuulrllrlrlrllrl…….

也就是 u 操作只會被用在開頭,那麼處於這個性質,我們可以對初始串(起點)維護乙個棧(維護 lr 方向) ,那麼每次遇到 u 操作就取出棧頂,判斷需要加入哪種新點。

更簡單的理解就是,因為可以跳過點,所以每個能走到的點都可以是終點,所以把它們都塗黑。這樣,有新操作的時候,就把它們的左/右兒子也塗黑就行(不用建樹,dp就行,見**);而對於找父親的操作,因為下面的點都是由父親走到的,所以只用關心最上面的那個點還有沒有父親,可不可以更新(見**)。

#include using namespace std;

typedef long long ll;

const int maxn=1e5+5,mod=1e9+7;

int n,m;

char t[maxn];

ll ans,f[4];

//f[1]表示只走過左兒子的點的個數,f[2]表示只走過右兒子的點的個數;

// f[0]表示兩個兒子都沒走過的點的個數,f[3]表示兩個兒子都走過的點的個數;

char s1[maxn],s2[maxn];

int main(){

scanf("%s", s1);

int len1 = strlen(s1);

for(int i=0; i

牛客 Wannafly模擬賽4 A

fst是一名可憐的小朋友,他很強,但是經常fst,所以rating一直低迷。但是重點在於,他非常適合acm!並在最近的區域賽中獲得了不錯的成績。拿到獎金後fst決定買一台新筆記本,但是fst發現,在 能承受的範圍內,筆記本的記憶體和速度是不可兼得的。可是,有一些筆記本是被另外一些 完虐 的,也就是記...

20200718模擬賽4題解

題目描述 輸入格式 輸出格式 樣例輸入 4 20 300 40 400 340 700 360 600樣例輸出 415 include include include define ll long long define int long long using namespace std const...

Wannafly模擬賽4 C Sum(線段樹)

考慮維護乙個這樣的問題 1 給出乙個陣列a,標號為1 n 2 修改陣列中的乙個位置。3 詢問區間 l,r 中所有子集的位運算and之和mod 10 9 7 位運算and即為 pascal中的and 和 c c 中的 我們定義集合s 若集合t,t s t,則稱t為s的子集 設f t a t1 and ...