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 ...