二分
P5502 [JSOI2015] 最大公约数
二分真恶心人。
对于这类题目,显然可以枚举左端点,向右快速跳合法的右端点。
发现 \(gcd\) 一旦减小就一定至少除以 \(2\) ,那么显然对于一个左端点,二分右端点只会二分 \(logV\) 次,那么总体复杂度就是 \(lognlogV\)
再加上 \(gcd\) 的复杂度 \(logV\),那么时间复杂度为 \(O(n\log n \log ^2V)\)
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+(r-l)/2)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 1e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , a[N] , ans , lg[N];
struct ST
{
int st[N][26];
void init()
{
for ( int i = 1 ; i <= n ; i ++ ) st[i][0] = a[i];
for ( int j = 1 ; j <= __lg(n) ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
st[i][j] = __gcd ( st[i][j-1] , st[i+(1<<j-1)][j-1] );
}
int query ( int l , int r )
{
int len = __lg(r-l+1);
return __gcd ( st[l][len] , st[r-(1<<len)+1][len] );
}
}st;
int que ( int x , int y )
{
int tmp = st.query ( x , y );
int l = x , r = n;
while ( l <= r )
{
if ( st.query ( x , mid ) < tmp ) r = mid - 1;
else l = mid + 1;
}
return r;
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
int T = read();
while ( T -- )
{
ans = 0;
n = read();
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
st.init();
for ( int l = 1 ; l <= n ; l ++ )
{
int r = l;
while ( r <= n )
{
int tmpr = que ( l , r );
ans = max ( ans , st.query ( l , r ) * ( tmpr - l + 1 ) );
r = tmpr + 1;
}
}
cout << ans << endl;
}
return 0;
}
P1020 [NOIP1999 普及组] 导弹拦截
第一问是求最长不升子序列,第二问是求最长上升子序列。
\(O(n^2)\):
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define mid (l+r>>1)
#define getchar() cin.get()
#define print(x) cout<<#x<<'='<<x<<endl
const int N = 1e5 + 5;
int read()
{
int f = 1 , x = 0;
char ch = getchar();
while ( !isdigit(ch) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit(ch) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , f[N] , ans , a[N] , g[N];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
while ( cin >> a[++n] ); -- n;
for ( int i = 1 ; i <= n ; i ++ ) f[i] = g[i] = 1;
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j < i ; j ++ )
if ( a[i] <= a[j] ) f[i] = max ( f[i] , f[j] + 1 );
for ( int i = 1 ; i <= n ; i ++ ) ans = max ( ans , f[i] );
cout << ans << endl;
ans = 0;
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j < i ; j ++ )
if ( a[i] > a[j] ) g[i] = max ( g[i] , g[j] + 1 );
for ( int i = 1 ; i <= n ; i ++ ) ans = max ( ans , g[i] );
cout << ans << endl;
return 0;
}