第一题:
sort
一遍,然后扫一遍数列,维护一个
l
(第一个比
复杂度:
o(nlogn)
第二题:
k
个连续的数相乘的乘积最大,
复杂度:
o(n)
第三题:
考虑每一个节点对最终答案的影响,即每一个节点在多少联通块中。这样用树形
dp
就搞定了。
dpi[i]
代表在
i
的子树中包含
最终答案就是
复杂度: o(n)
第四题
个人感觉蛮不错的题。和
hihocoder
那题的思路有点像。
i|j
和
i
&
然后去掉公共部分
y
,在剩下来的二进制位(
用
stl
少写一个二分。
复杂度:
o(3log2nlog2n)
第五题
二分最终的答案。在原序列中,如果
>=mid
的,就标记为
1
,否则就标记为
做到这里就是一个线段树的区间求和和修改操作。
感觉这个想法很不错!!!
复杂度:
o(m(logn)2)
给一个第四题的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef vector <int> VI;
typedef pair <int,int> PII;
#define FOR(i,x,y) for(int i = x;i < y;++ i)
#define IFOR(i,x,y) for(int i = x;i > y;-- i)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
const int maxn = 1<<14;
VI G[maxn];
int n,m;
void init(){
FOR(i,1,maxn){
for(int j = i;j;j = (j-1)&i) G[i].pb(j);
G[i].pb(0);
reverse(G[i].begin(),G[i].end());
}
}
int calc(int x,int n,int m){
if(n < 0 || m < 0) return 0;
return lower_bound(all(G[x]),n+1) - lower_bound(all(G[x]),x-m);
}
void work(){
LL ans = 0;
FOR(i,1,maxn){
FOR(j,0,sz(G[i])){
int x = i,y = G[i][j];
if((x^y) > (n+m-2*y)) continue;
if(x == y && x <= n && x <= m) {ans += x;continue;}
int cnt = calc(x^y,n-y,m-y);
if(!y){
if(x <= n) cnt --;
if(x <= m) cnt --;
}
ans += __gcd(x,y)*(LL)cnt;
}
}
printf("%I64d\n",ans);
}
int main(){
int T; scanf("%d",&T);
init();
while(T--){
scanf("%d%d",&n,&m);
work();
}
return 0;
}