昨天来了一波非常激情的liaoliao四连做..
然后我很幸运的脑(bao)短(ling)路(le)..
今天又很开森的bak回这四道挺好的题啊..
先把每个数拆成 a×2b ,按照位来dp..
fi,j 表示在 j×2i 以内的最高价值..
然后就背包搞一下就好了,注意从 i 递推到 i+1 的状况..
如果 w 的第 i 位是 0 ,那么对于 fi,k (k mod 2==1) ,就要递推到 fi+1,k+12 ,因为已经没有可能在后面再涉及到第 i 位的状态了..
#include
#include
#include
#include
using namespace std;
int f[32][1010];
struct node {
int a, b, val;
}list[110];
int n, W, len, w[32];
int lowbit ( int x ){ return x & (-x); }
bool cmp ( node x, node y ){ return x.b < y.b; }
int _max ( int x, int y ){ return x > y ? x : y; }
int main (){
int i, j, k;
while ( scanf ( "%d%d", &n, &W ) && n >= 0 && W >= 0 ){
len = -1;
while (W){
w[++len] = W%2;
W /= 2;
}
for ( i = 1; i <= n; i ++ ){
int x;
scanf ( "%d%d", &x, &list[i].val );
list[i].b = lowbit (x);
list[i].a = x/list[i].b;
}
memset ( f, 0, sizeof (f) );
sort ( list+1, list+n+1, cmp );
int maxl = 0;
j = 1;
for ( i = 0; i <= len; i ++ ){
while ( list[j].b == (1<for ( k = maxl; k >= 0; k -- ) f[i][k+list[j].a] = _max ( f[i][k+list[j].a], f[i][k]+list[j].val );
maxl += list[j].a;
j ++;
}
if ( w[i] == 0 ){
for ( k = 0; k <= maxl; k ++ ){
if ( k & 1 ) f[i+1][(k+1)/2] = _max ( f[i+1][(k+1)/2], f[i][k] );
else f[i+1][k/2] = _max ( f[i+1][k/2], f[i][k] );
}
if ( maxl & 1 ) maxl = (maxl+1) >> 1;
else maxl = maxl >> 1;
}
else {
for ( k = 0; k <= maxl; k ++ ) f[i+1][k/2] = _max ( f[i+1][k/2], f[i][k] );
maxl = maxl >> 1;
}
}
printf ( "%d\n", _max ( f[len][0], f[len][1] ) );
}
return 0;
}
搞个后缀数组..
二分答案串,然后在原串中匹配,匹配到如果某个位置字典序比答案串该位置的要大,那么证明在这段区间必须要砍一刀..
那么就转化成一个很经典的贪心问题了: n 条线段,找最少的点使得每条线段至少有一个点..
先去掉包含的线段,再把剩余线段按照左端点排序,每次选择第一条线段的右端点,直到遇到某个左端点在该右端点右边..
#include
#include
#include
#include
using namespace std;
const int Maxn = 100010;
int sa[Maxn], rank[Maxn], y[Maxn], wr[Maxn], hei[Maxn];
int Rsort[Maxn];
char s[Maxn]; int n;
int K, o[Maxn], rig[Maxn];
int _min ( int x, int y ){ return x < y ? x : y; }
bool cmp ( int k1, int k2, int ln ){ return wr[k1] == wr[k2] && wr[k1+ln] == wr[k2+ln]; }
void get_sa ( int m ){
int i, j, k;
memset ( Rsort, 0, sizeof (Rsort) );
for ( i = 1; i <= n; i ++ ) Rsort[rank[i]] ++;
for ( i = 1; i <= m; i ++ ) Rsort[i] += Rsort[i-1];
for ( i = n; i >= 1; i -- ) sa[Rsort[rank[i]]--] = i;
int p = 1, ln = 1;
while ( p < n ){
k = 0;
for ( i = n-ln+1; i <= n; i ++ ) y[++k] = i;
for ( i = 1; i <= n; i ++ ){
if ( sa[i]-ln > 0 ) y[++k] = sa[i]-ln;
}
for ( i = 1; i <= n; i ++ ) wr[i] = rank[y[i]];
memset ( Rsort, 0, sizeof (Rsort) );
for ( i = 1; i <= n; i ++ ) Rsort[wr[i]] ++;
for ( i = 1; i <= m; i ++ ) Rsort[i] += Rsort[i-1];
for ( i = n; i >= 1; i -- ) sa[Rsort[wr[i]]--] = y[i];
memcpy ( wr, rank, sizeof (wr) );
p = 1; rank[sa[1]] = 1;
for ( i = 2; i <= n; i ++ ){
if ( !cmp ( sa[i], sa[i-1], ln ) ) p ++;
rank[sa[i]] = p;
}
m = p; ln *= 2;
}
}
void get_hei (){
int i, j, k;
k = 0;
for ( i = 1; i <= n; i ++ ){
j = sa[rank[i]-1];
if (k) k --;
while ( s[i+k] == s[j+k] ) k ++;
hei[rank[i]] = k;
}
}
int bit[Maxn], f[Maxn][20];
int qu ( int x, int y ){
if ( x == y ) return 0x7fffffff;
if ( x > y ) swap ( x, y );
int le = y-x;
return _min ( f[x][bit[le]], f[y-(1<struct que {
int x, ri;
}list[Maxn]; int tp;
int main (){
int i, j, k;
scanf ( "%d", &K );
scanf ( "%s", s+1 );
n = strlen (s+1);
for ( i = 1; i <= n; i ++ ) rank[i] = s[i];
get_sa (190);
get_hei ();
int l = 1, r, ret;
for ( i = 1; i <= n; i ++ ){
o[i] = o[i-1]+n-sa[i]+1-hei[i];
}
r = o[n];
bit[1] = 0;
for ( i = 2; i <= n; i ++ ){
if ( (1<<(bit[i-1]+1)) <= i ) bit[i] = bit[i-1]+1;
else bit[i] = bit[i-1];
}
for ( i = n; i >= 1; i -- ){
f[i][0] = hei[i+1];
for ( j = 1; j <= 17 && i+(1<<(j-1)) <= n; j ++ ) f[i][j] = _min ( f[i][j-1], f[i+(1<<(j-1))][j-1] );
}
while ( l <= r ){
int mid = ( l + r ) >> 1;
int pos = lower_bound ( o+1, o+n+1, mid ) - o;
int len = hei[pos]+mid-o[pos-1];
bool bk = true;
tp = 0;
for ( i = 1; i <= n; i ++ ){
rig[i] = -1;
int re = _min ( qu ( rank[i], pos ), len );
if ( re == len ) rig[i] = i+re;
else if ( s[i+re] > s[sa[pos]+re] ) rig[i] = i+re;
if ( rig[i] <= i && rig[i] != -1 ){ bk = false; break; }
if ( rig[i] != -1 ){
while ( tp > 0 && list[tp].ri > rig[i] ){
rig[list[tp].x] = -1;
tp --;
}
tp ++;
list[tp].x = i; list[tp].ri = rig[i];
}
}
if ( bk == false ){ l = mid+1; continue; }
int sum = 0, last = 0;
for ( i = 1; i <= tp; i ++ ){
if ( last < list[i].x ){
last = list[i].ri-1;
sum ++;
}
}
if ( last == n ) sum --;
if ( sum <= K-1 ){ ret = mid; r = mid-1; }
else l = mid+1;
}
int pos = lower_bound ( o+1, o+n+1, ret ) - o;
int len = hei[pos]+ret-o[pos-1];
for ( i = 1; i <= len; i ++ ) printf ( "%c", s[sa[pos]+i-1] );
printf ( "\n" );
return 0;
}
好好想想,无论怎么变,对于每个点改变的只有这个点右边比它小的点的个数..
那么就套个线段树搞搞就好了..
mdzz.. 差点就a了..
#include
#include
#include
#include
#define LL long long
using namespace std;
const LL Maxn = 500010;
LL a[Maxn], b[Maxn], bl;
LL n, m, ans, pos, poso;
LL seg[Maxn*4], num[Maxn*4], rig[Maxn];
void change ( LL now, LL L, LL R, LL x ){
if ( L == R ){ seg[now] ++; return; }
LL mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( x <= mid ) change ( lc, L, mid, x );
else change ( rc, mid+1, R, x );
seg[now] = seg[lc]+seg[rc];
}
LL query ( LL now, LL L, LL R, LL l, LL r ){
if ( l > r ) return 0;
if ( L == l && R == r ) return seg[now];
LL mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( r <= mid ) return query ( lc, L, mid, l, r );
else if ( l > mid ) return query ( rc, mid+1, R, l, r );
else return query ( lc, L, mid, l, mid ) + query ( rc, mid+1, R, mid+1, r );
}
void bulid_tree ( LL now, LL L, LL R ){
if ( L < R ){
LL mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
bulid_tree ( lc, L, mid );
bulid_tree ( rc, mid+1, R );
if ( seg[lc] < seg[rc] ){ num[now] = num[lc]; seg[now] = seg[lc]; }
else { num[now] = num[rc]; seg[now] = seg[rc]; }
}
else { num[now] = L; seg[now] = lower_bound ( b+1, b+bl+1, a[L] ) - b; }
}
void ch ( LL now, LL L, LL R, LL x ){
if ( L == R ){ seg[now] = 0x7fffffff; return; }
LL mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( x <= mid ) ch ( lc, L, mid, x );
else ch ( rc, mid+1, R, x );
if ( seg[lc] < seg[rc] ){ num[now] = num[lc]; seg[now] = seg[lc]; }
else { num[now] = num[rc]; seg[now] = seg[rc]; }
}
void qu ( LL now, LL L, LL R, LL l, LL r ){
if ( L == l && R == r ){
if ( seg[now] < poso ){
poso = seg[now];
pos = num[now];
}
return;
}
LL mid = ( L + R ) >> 1, lc = now*2, rc = now*2+1;
if ( r <= mid ) qu ( lc, L, mid, l, r );
else if ( l > mid ) qu ( rc, mid+1, R, l, r );
else qu ( lc, L, mid, l, mid ), qu ( rc, mid+1, R, mid+1, r );
}
int main (){
LL i, j, k;
scanf ( "%lld%lld", &n, &m );
for ( i = 1; i <= n; i ++ ) scanf ( "%lld", &a[i] ), b[i] = a[i];
sort ( b+1, b+n+1 );
bl = unique ( b+1, b+n+1 ) - (b+1);
ans = 0;
for ( i = n; i >= 1; i -- ){
LL x = lower_bound ( b+1, b+bl+1, a[i] ) - b;
rig[i] = query ( 1, 1, bl, 1, x-1 );
ans += rig[i];
change ( 1, 1, bl, x );
}
printf ( "%lld\n", ans );
bulid_tree ( 1, 1, n );
for ( i = 1; i <= m; i ++ ){
LL o;
scanf ( "%lld", &o );
LL x = lower_bound ( b+1, b+bl+1, a[o] ) - b;
while ( poso = 0x7fffffff, qu ( 1, 1, n, o, n ), poso <= x ){
ans -= rig[pos];
ch ( 1, 1, n, pos );
}
printf ( "%lld\n", ans );
}
return 0;
}
容斥原理啊..
一个很高深的原理..
先把原问题转成映射的问题..
然后 fi,j 表示把 i 映射到 j 的方案数..
最后答案就等于至少0个禁止选的-至少1个禁止选的+至少2个禁止选的..
jiry_2的blog
#include
#include
#include
#include
#define LL long long
using namespace std;
const int Maxn = 20;
LL f[Maxn][Maxn];
struct node {
int y, next;
}a[Maxn*Maxn*2], af[Maxn*2]; int first[Maxn], firstf[Maxn], len, lenf;
int n, m;
void ins ( int x, int y ){
len ++;
a[len].y = y;
a[len].next = first[x]; first[x] = len;
}
void insf ( int x, int y ){
lenf ++;
af[lenf].y = y;
af[lenf].next = firstf[x]; firstf[x] = lenf;
}
LL ans;
bool v[Maxn];
void calc ( int x, int fa ){
int i, j;
for ( int k = firstf[x]; k; k = af[k].next ){
int y = af[k].y;
if ( y == fa ) continue;
calc ( y, x );
}
for ( i = 1; i <= n; i ++ ){
if ( v[i] == false ) continue;
f[x][i] = 1;
for ( int k = firstf[x]; k; k = af[k].next ){
int y = af[k].y;
if ( y == fa ) continue;
LL ret = 0;
for ( int ki = first[i]; ki; ki = a[ki].next ){
int yy = a[ki].y;
if ( v[yy] == false ) continue;
ret += f[y][yy];
}
f[x][i] *= ret;
}
}
}
void check (){
memset ( f, 0, sizeof (f) );
calc ( 1, 0 );
LL ret = 0; int sum = 0;
for ( int i = 1; i <= n; i ++ ){
if ( v[i] == true ){ ret += f[1][i]; sum ++; }
}
//printf ( "%d %d\n", sum, ret );
if ( (n-sum) % 2 == 0 ) ans += ret;
else ans -= ret;
}
void dfs ( int x ){
if ( x == n+1 ){ check (); return; }
v[x] = false;
dfs (x+1);
v[x] = true;
dfs (x+1);
}
int main (){
int i, j, k;
scanf ( "%d%d", &n, &m );
for ( i = 1; i <= m; i ++ ){
int x, y;
scanf ( "%d%d", &x, &y );
ins ( x, y ); ins ( y, x );
}
for ( i = 1; i < n; i ++ ){
int x, y;
scanf ( "%d%d", &x, &y );
insf ( x, y ); insf ( y, x );
}
dfs (1);
printf ( "%lld\n", ans );
return 0;
}