题目大意:在一个n*n的棋盘上有一些棋子,每个棋子i有一个值pi。有一个常数c。有一棋子集合定义如下,集合中所有棋子都在同一对角线上,因为在同一对角线上,其横坐标可以标定棋子的位置,集合中任意两个棋子i,j(i<j)之间满足j-i+1>=pj^2+pi^2+c。求最大的集合。
题解:
首先这个集合中的元素具有传递性,若i,j(i<j)属于同一个集合,且j,k(j<k)属于同一个集合,则i,k属于同一集合。
可以用dp求最大集合,dp[i]表示第i个元素结尾能够取得的最大集合大小。然后在前面找到满足i-j+1>=pi^2+pj^2+c的dp[j]值最大的j。注意到移项之后上式变为-pj^2-j>=pi^2-i+c-1,这样就可以进行离散化,用树状数组维护最大值。
解法2:
能够通过集合的定义发现,可以将每个棋子看作是一条线段,最后要求的其实就是最大不相交线段覆盖。这是一个经典问题,可贪心解。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
struct node{
int x;shuzhuang
ll p;
node(int x,ll p):x(x),p(p){}
node(){}
bool operator<(const node &a)const{
return x<a.x;
}
};
vector<node> ar[2][maxn<<1];
ll des[maxn<<1];
int nn;
int bit[maxn<<1];
int lowbit(int x)
{
return x&(-x);
}
void init(int n)
{
for(int i = 1; i <= n; i++) bit[i] = 0;
for(int i = 1; i <= n; i++)
{
int l = i + lowbit(i);
bit[l] = max(bit[l],bit[i]);
}
}
int query(int n)
{
int ans = 0;
while(n)
{
ans =max(ans,bit[n]);
n -= lowbit(n);
}
return ans;
}
void update(int pos,int change)
{
while(pos <= maxn)
{
bit[pos] = max(bit[pos],change);
pos += lowbit(pos);
}
}
bool cmp(int a,int b){
return a>b;
}
int _find(ll x){
int ret;
ret = lower_bound(des,des+nn,x)-des;
ret = nn-ret;
//printf("x = %I64d id = %d\n",x,ret);
return ret;
}
int main(){
freopen("bishops.in","r",stdin);
int T,n,m,c;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&c);
for(int i = 0;i < 2;i++) for(int j = 0;j <= n*2+1;j++) ar[i][j].clear();
for(int i = 0;i < m;i++){
int a,b;
ll p;
scanf("%d%d%I64d",&a,&b,&p);
p *= p;
ar[0][a+b-1].push_back(node(a,p));
ar[1][a-b+n].push_back(node(a,p));
}
for(int i = 0;i < 2;i++){
for(int j = 1;j < 2*n;j++){
sort(ar[i][j].begin(),ar[i][j].end());
}
}
int ans = 0;
for(int i = 0;i < 2;i++){
for(int j = 1;j < 2*n;j++){
nn = 0;
for(int k = 0;k < ar[i][j].size();k++){
int x;
ll p;
x = ar[i][j][k].x;
p = ar[i][j][k].p;
des[nn++] = -p-x;
des[nn++] = p-x+c-1;
}
sort(des,des+nn);
nn = unique(des,des+nn)-des;
//for(int i = 0;i < nn;i++) printf("%d ",des[i]);
//if(nn) printf("\n");
init(nn);
for(int k = 0;k < ar[i][j].size();k++){
int x;
ll p;
x = ar[i][j][k].x;
p = ar[i][j][k].p;
int tmp,id;
id = _find(p-x+c-1);
tmp = query(id);
id = _find(-p-x);
update(id,tmp+1);
ans = max(ans,tmp+1);
}
//for(int i = 1;i <= nn;i++){
// printf("%I64d %d\n",des[nn-i],bit[i]);
//}
//if(nn)
//printf("%d\n\n",ans);
}
}
printf("%d\n",ans);
//printf("=======================================================================\n");
}
return 0;
}
//1.ar数组开小了,re了
//2.lowerbound只能对升序的二分,把des排成降序的,结果没法二分..sb了
//3.des数组开始开成int型的了,应该是ll
//4.公式推错 - - 该打!
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100010;
struct node{
int x;
ll p;
node(int x,ll p):x(x),p(p){}
node(){}
bool operator<(const node &a)const{
if(1ll*x-p==1ll*a.x-a.p) return p+x<a.p+a.x;
return 1ll*x-p<1ll*a.x-a.p;
}
};
vector<node> ar[2][maxn<<1];
int main(){
freopen("bishops.in","r",stdin);
int T,n,m,c;
scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&c);
for(int i = 0;i < 2;i++) for(int j = 0;j <= n*2+1;j++) ar[i][j].clear();
for(int i = 0;i < m;i++){
int a,b;
ll p;
scanf("%d%d%I64d",&a,&b,&p);
p *= p;
ar[0][a+b-1].push_back(node(a,p));
ar[1][a-b+n].push_back(node(a,p));
}
for(int i = 0;i < 2;i++){
for(int j = 1;j < 2*n;j++){
sort(ar[i][j].begin(),ar[i][j].end());
}
}
int ans = 0;
for(int i = 0;i < 2;i++){
for(int j = 1;j < 2*n;j++){
ll r;
int tmp = 0;
for(int k = 0;k < ar[i][j].size();k++){
ll temp = ar[i][j][k].p+ar[i][j][k].x;
ll l = 1ll*ar[i][j][k].x-ar[i][j][k].p;
//printf("k=%d temp=%I64d r=%I64d\n",k,temp,r);
if(k == 0){
r = temp;
tmp = 1;
}
else{
if(l+1>=r+c){
tmp++;
r = temp;
}
else{
if(temp < r){
r = temp;
}
}
}
}
ans = max(ans,tmp);
}
}
printf("%d\n",ans);
//printf("=======================================================================\n");
}
return 0;
}