Đề bài:
Thuật toán:
- Sử dụng phương pháp quy hoạch động kết hợp với bitmask.
- Sắp xếp lại mảng A.
- f[i,state] là số phần tử cần loại bỏ của dãy A[1..i] khi có state là trạng thái giữ hoặc chọn của 10 số cuỗi của dãy.
Code:
- C++ (ideone)
#include
#define FORE(i, a, b) for(int i = a; i <= b; ++i)
#define FORD(i, a, b) for(int i = a; i >= b; --i)
#define FOR(i, a, b) for(int i = a; i < b; ++i)
#define X first
#define Y second
#define ll long long
#define mp make_pair
#define pb push_back
#define endl '\n'
const int MAXN = 1e5 * 5;
const int inf = 1024;
const int N = 5000;
using namespace std;
int n,p[N],a[N],b[N],l[N],ans,ss,c[N],f[2001][1025];
void update()
{
int cnt = 0;
int dem = 0;
FORE(i,1,min(n,10))
if (l[i])
c[++cnt] = a[i],dem += b[i];
sort(c+1,c+cnt+1);
FORE(i,1,cnt)
FORD(j,i-1,1)
if (c[i] - c[j] > 9) break;
else
{
if (c[i] - c[j] == 1) return;
if (c[i] - c[j] == 8) return;
if (c[i] - c[j] == 9) return;
}
f[10][ss] = dem;
ans = max(ans , dem);
}
void duyet(int i)
{
FORE(j,0,1)
{
ss = ss*2 + j;
l[i] = j;
if (i == min(n,10)) update();
else duyet(i+1);
ss /= 2;
}
}
int ok(int u,int v)
{
if (u - v == 1) return 1;
if (u - v == 8) return 1;
if (u - v == 9) return 1;
return 0;
}
int check(int s,int i)
{
FORE(j,0,8)
{
int xx = (s >> j)&1;
if (xx && ok(a[i],a[i - j - 1])) return 1;
}
return 0;
}
int main()
{
ios_base::sync_with_stdio(0); cin.tie(0);
#ifndef ONLINE_JUDGE
freopen("", "r", stdin);
freopen("", "w", stdout);
#endif //yeulaptrinh.de
cin>>n;
int lx = n;
FORE(i,1,n) cin>>p[i];
sort(p+1,p+n+1);
int po = -1;
int n1 = 0;
FORE(i,1,n)
if (p[i] != po)
{
po = p[i];
++n1;
a[n1] = p[i];
++b[n1];
}
else ++b[n1];
n = n1;
duyet(1);
if (n <= 10)
{
cout<
- Pascal (ideone)
uses math;
const
fi = '';
var
a,b,cnt : array[0..2001] of longint;
f : array[0..2001,0..511] of longint;
dd : array[0..2001,0..511] of boolean;
n,n1 : longint;
procedure enter;
var
i : longint;
begin
assign(input,fi);
reset(input);
readln(n);
for i := 1 to n do
read(b[i]);
close(input);
end;
procedure qsort(l,r : longint);
var
i,j,k,tmp : longint;
begin
i := l;
j := r;
k := b[l + random(r - l + 1)];
while i < j do
begin
while b[i] < k do inc(i);
while b[j] > k do dec(j);
if i <= j then
begin
tmp := b[i];
b[i] := b[j];
b[j] := tmp;
inc(i);
dec(j);
end;
end;
if l < j then qsort(l,j);
if i < r then qsort(i,r);
end;
function getbit(x,i : longint) : longint;
begin
exit(1 and (x shr (i - 1)));
end;
function check(stt : longint) : boolean;
begin
if (getbit(stt,1) = 1) or (getbit(stt,8) = 1) or (getbit(stt,9) = 1) then exit(false);
exit(true);
end;
function batbit(x,i : longint) : longint;
begin
exit(x or (1 shl (i - 1)));
end;
function sttnext(tt,stt,i : longint) : longint;
var
res,kc,j : longint;
begin
kc := a[i+1] - a[i];
res := 0;
for j := 0 to 9 - kc do
if j = 0 then
begin
if tt = 1 then res := batbit(res,kc)
end
else
if getbit(stt,j) = 1 then
res := batbit(res,kc + j);
exit(res);
end;
procedure init;
var
i,j : longint;
begin
qsort(1,n);
a[1] := b[1];
j := 1;
cnt[1]:=1;
for i := 2 to n do
if b[i] <> a[j] then
begin
inc(j);
a[j] := b[i];
cnt[j] := 1;
end
else inc(cnt[j]);
n1:=j;
a[n1+1] := high(longint)
end;
function cal(i,stt: longint) : longint;
var
ff : longint;
begin
if dd[i,stt] then exit(f[i,stt]);
dd[i,stt] := true;
if i = n1 + 1 then
ff := 0
else
begin
ff := cal(i + 1,sttnext(0,stt,i)) + cnt[i];
if check(stt) then
ff := min(ff,cal(i + 1,sttnext(1,stt,i)));
end;
f[i,stt] := ff;
exit(ff);
end;
procedure print;
begin
writeln(cal(1,0));
end;
begin
enter;
init;
print;
end.
viết rõ ràng 1 tí được k,viết rõ tác dụng của từng mạng đọc cho dễ hiểu
OK. Mình đã viết thêm.
anh giải thích rõ hơn được không ạ, tại sao lại chỉ xét 10 số cuối
Vì sau khi sort lại mảng A thì khoảng cách lớn nhất giữa hai số hiệu bằng 9 là 10
Vd: A = {…,11,12…19,20,…}
Sẽ thấy 20-11=9
Bạn suy nghĩ thêm nhé
Anh có code Pascal không anh admin ơi, cho em xin với
Mình đã thêm code Pascal vào bài viết.
tks anh !!!