【刷题计划】POI做题记录

POI 2015

4384: [POI2015]Trzy wieże

claris的题解很详细
总结:
把区间不等关系写成前缀和形式----化成两点的不等
(x,y,z)三元组任意一维不等,则可以一维排序,一维树状数组,查询不同色的最大值、最小值
一开始感觉代码很乱,不知道自己的实现是否有错。
其实逻辑非常清楚,需要注意的只有变量名
还有为了防止下标<=0,加上n + 10,如果刚好+n会有=0的下标。

#include
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const int maxn = 1e6 + 20;
const int inf = 1e9;

int mx_id[2][maxn * 2],mn[2][maxn * 2],mn2[2][maxn * 2],mx[2][maxn * 2],mx2[2][maxn * 2],mn_id[2][maxn * 2];

int a[220];
int n,ans,cnt[maxn][3];
char ch[maxn];
struct node{
	int a,b,c,id;
	bool operator < (node x)const{
		return a < x.a;
	}
}dt[maxn];

inline int query(int t,int pos,int c,int id){
	if ( pos <= 0 ) return 0;
	int l = inf , r = 0;
	fordown(i,pos){
		if ( mx_id[t][i] == c ){
			r = max(r,mx2[t][i]);
		}
		else r = max(r,mx[t][i]);
		if ( mn_id[t][i] == c ){
			l = min(l,mn2[t][i]);
		}
		else l = min(l,mn[t][i]);
	}
//	cout<
	return max(0,max(id - l,r - id));
}
inline void modify(int t,int pos,node x){
	forup(i,pos,n * 2 + 10){
		if ( mx[t][i] < x.id ){
			if ( mx_id[t][i] != x.c ) mx2[t][i] = mx[t][i];
			mx_id[t][i] = x.c , mx[t][i] = x.id;
		}
		else if ( mx2[t][i] < x.id && x.c != mx_id[t][i] ){
			mx2[t][i] = x.id;
		}
		if ( mn[t][i] > x.id ){
			if ( mn_id[t][i] != x.c ) mn2[t][i] = mn[t][i];
			mn_id[t][i] = x.c , mn[t][i] = x.id;
		}
		else if ( mn2[t][i] > x.id && x.c != mn_id[t][i] ){
			mn2[t][i] = x.id;
		}
	}
}
int main(){
	scanf("%d%s",&n,ch + 1);
	n = strlen(ch + 1);
	a['B'] = 0 , a['C'] = 1 , a['S'] = 2;
	dt[0] = (node){0,0,0,0};
	rep(i,1,n){
		rep(k,0,2) cnt[i][k] = cnt[i - 1][k] + (a[ch[i]] == k);
		int a = cnt[i][0] - cnt[i][1] , b = cnt[i][1] - cnt[i][2] , c = cnt[i][2] - cnt[i][0];
		dt[i] = (node){a,b,c,i};
	}
	rep(i,1,n * 2 + 10) rep(t,0,1) mn[t][i] = mn2[t][i] = inf;
	sort(dt,dt + n + 1);
	int last = 0;
//	cout<<"dt : \n";
//	rep(i,0,n) 	cout<
	rep(i,0,n){	
		if ( i && dt[i].a != dt[i - 1].a ){
			rep(j,last,i - 1){
				modify(0,dt[j].b + n + 10,dt[j]);
				modify(1,n - dt[j].b + 10,dt[j]);
			}
			last = i;
		}
		ans = max(ans,query(0,dt[i].b - 1 + n + 10,dt[i].c,dt[i].id));
		ans = max(ans,query(1,n - dt[i].b - 1 + 10,dt[i].c,dt[i].id));
	}
//	rep(j,last,n){
//		ans = max(ans,query(0,dt[j].b - 1 + n,dt[j].c,dt[j].id));
//		ans = max(ans,query(1,n - dt[j].b - 1,dt[j].c,dt[j].id));	
//	}
	int p = 1;
	rep(i,1,n){
		if ( ch[p] != ch[i] ) p = i;
		ans = max(ans,i - p + 1);
	}
	cout<<ans<<endl;
}

POI 2017

感觉这套题很水,但是没有发现很多trick,被题目绕进去了,比如那道数论,真不知道这个结论
2019.3.18

4723: [POI2017]Flappy Bird

直接贪心就好
注意根据奇偶性特判不可达位置

一开始把题意读错了,如果任给一些区间做障碍物这道题更有意思
做法是首先把高度变成x + h,这样就不用下降(好想)。还可以把坐标除/2,这样可达变成了连续的,不用考虑奇偶性。
然后维护每个横坐标的可达区间,横坐标加就是整体shift(右端点右移)。用堆和set维护第一个R和L相撞
加入一个不可达区间相当于加入两个端点

bzoj4724 [POI2017]Podzielno 数论

结论:a∗Bk≡a(mod B−1)
所以最多只会删除一位,a[i] >= 1
直接二分前缀和

bzoj4725: [POI2017]Reprezentacje ró?nicowe 找性质

奇数乘2可以发现增长到1e9是log级别的
偶数取mex相当于每次mex加一(遇到已有的数跳过)
当偶数>1e9就对mex没有任何影响。所以暴力跑出小数的差,用map存起来,其他数只可能是相邻的偶-奇,二分一下

不能盲目的打表
要从递推式本身出发找性质。关联数据范围。
一开始只知道打表什么都没有发现,看了题解才想到,很不应该!

#include
using namespace std;
 
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
 
const int inf = 1e9;
const int N = 3e6 + 10;
const int maxn = 100020;
const ll mod = 1e9 + 7;
 
 
int a[maxn];
int n,tot,cnt,b[maxn];
map <int,int> vis;
map <int,pr> dt;
 
int getmex(int n){
    vis.clear();
    rep(i,1,n){
        rep(j,1,i - 1){
            int x = abs(a[i] - a[j]);
            vis[x] = 1;
        }
    }
    int res = 1;
    while ( vis[res]) res++;
    return res;
}
void init(){
    a[1] = 1 , a[2] = 2;
    rep(i,3,1000){
        if ( i & 1 ) a[i] = a[i - 1] * 2;
        else{
            a[i] = a[i - 1] + getmex(i - 1);
            if ( a[i] > inf ){ tot = i; break; }
        }
    }   
    rep(i,1,tot) rep(j,1,i - 1){
        dt[a[i] - a[j]] = mp(i,j);
        b[++cnt] = a[i] - a[j];
    }
    sort(b + 1,b + cnt + 1);
//  rep(i,1,cnt) cout<
}
void solve(){
    int x;
    scanf("%d",&x);
    if ( dt.find(x) != dt.end()  ) printf("%d %d\n",dt[x].fi,dt[x].se);
     
    else{
        int c = lower_bound(b + 1,b + cnt + 1,x) - b - 1;
        printf("%d %d\n",tot + (x - c) * 2,tot + (x - c) * 2 - 1);
    }
}
int main(){
    init();
    scanf("%d",&n);
    while ( n-- ){
        solve();
    }
}
bzoj 4726: [POI2017]Sabota? 树形DP

显然背叛叶子最劣
然后是一个简单的树形DP。当前点的最大比例=max(min(f[son],sz[son] / (sz[x] - 1))

一开始以为二分,根本没有想DP。
然后T飞、首先bzoj根本不知道有多少组数据。
这道题应该是一个很显然的树形DP,没有立即反应过来。还需要积累!

4727: [POI2017]Turysta 竞赛图+构造

竞赛图讲解

竞赛图一定存在哈密顿路径
强连通则有哈密顿回路
tarjian后在DAG上求最长路

板子写了1小时,对代码的实现能力不够,还需要提高

#include
using namespace std;
 
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
 
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
 
const ld inf = 2e18;
const int N = 3e6 + 10;
const int maxn = 2020;
const ll mod = 1e9 + 7;
 
int e[maxn][maxn];
int n;
int dfn[maxn],low[maxn],ins[maxn],st[maxn],tops,belong[maxn],tot,sz[maxn],dfstime;
int nxt[maxn][maxn],hh[maxn],tt[maxn];
int f[maxn],to[maxn];
vector <int> vec[maxn],P;
 
void clear(){
    rep(i,1,n){
        vec[i].clear();
        belong[i] = sz[i] = ins[i] = dfn[i] = low[i] = hh[i] = tt[i] = 0;
    }
    rep(i,1,n) rep(j,1,n) nxt[i][j] = 0;
    tops = dfstime = tot = 0;
}
void getpath(int nxt[],int &head,int &tail,const vector <int> &V){
    //找哈密顿路径
    head = tail = V[0];
    nxt[head] = 0;
    rep(i,1,V.size() - 1){
        int cur = V[i];
        if ( e[tail][cur] ) nxt[tail] = cur , tail = cur , nxt[cur] = 0;
        else if ( e[cur][head] ) nxt[cur] = head , head = cur;
        else{
            for (int x = head ; x ; x = nxt[x]){
                if ( e[x][cur] && e[cur][nxt[x]] ){
                    nxt[cur] = nxt[x] , nxt[x] = cur;
                    break;  
                }
            }   
        }
    }
    if ( head == tail ){
        nxt[tail] = head;
        return;
    }
    //找哈密顿回路
    //找最靠右的和head相连的节点
    int id = 0;
    for (int x = nxt[head] ; x ; x = nxt[x]){
        if ( e[x][head] ) id = x;
    }
    tail = id , P.clear();
    for (int x = nxt[id] ; x ; x = nxt[x]){
        P.pb(x);
    }
    if ( !P.size() ){
       nxt[tail] = head;
       return;
    }
    nxt[id] = 0;
    int pre = P[0];
    //从这个环开始扩大
    rvc(i,P){
        int cur = P[i],flag = 0;
        if ( !pre ) pre = cur;
        for (int x = head ; x ; x = nxt[x]){
            if ( e[x][pre] && e[cur][nxt[x]] ){
                nxt[cur] = nxt[x];
                nxt[x] = pre;
                flag = 1 , pre = 0;
                break;
            }
        }
//      if ( !flag ){
//          if ( pre != cur ) nxt[P[i - 1]] = P[i];
//      }
    }
    nxt[tail] = head;
}
void print_Path(int c){
    printf("%d ",hh[c]);
    for (int x = nxt[c][hh[c]] ; x != hh[c] ; x = nxt[c][x]){
        printf("%d ",x);
    }
}
void print_Path(int c,int y){
    printf("%d ",y);
    for (int x = nxt[c][y] ; x != y ; x = nxt[c][x]){
        printf("%d ",x);
    }
}
void dfs(int x){
    low[x] = dfn[x] = ++dfstime;
    st[++tops] = x , ins[x] = 1;
//  fore(i,x){
    rep(i,1,n){
        if ( !e[x][i] ) continue;
 
        if ( !dfn[i] ){
            dfs(i);
            low[x] = min(low[x],low[i]);
        }
        else if ( ins[i] ){
            low[x] = min(low[x],dfn[i]);
        }
    }
    if ( low[x] == dfn[x] ){
        ++tot;
        int s = st[tops--];
        while ( x != s){
            sz[tot]++ , belong[s] = tot , ins[s] = 0;
            vec[tot].pb(s);
            s = st[tops--];
        }
        vec[tot].pb(x);
        sz[tot]++ , belong[x] = tot , ins[x] = 0;
        getpath(nxt[tot],hh[tot],tt[tot],vec[tot]);
    //  print_Path(tot);
    }
 
}
 
void solve(){
    rep(i,1,tot){
        rvc(j,vec[i]){
            rep(k,1,n){
                if ( !e[vec[i][j]][k] ) continue;
                int c = belong[k];
                if ( c == i ) continue;
                if ( f[c] > f[i] ){
                    f[i] = f[c];
                    to[i] = c;
                }
            }
        }
        f[i] += sz[i];
    }
    rep(i,1,n){
        int c = belong[i];
        printf("%d ",f[c]);
        int x = c;
        print_Path(x,i) , x = to[x];
        while ( x ) print_Path(x) , x = to[x];
        puts("");
    }
}
 
int main(){
//  freopen("input.txt","r",stdin);
    scanf("%d",&n);
    rep(i,2,n){
        rep(j,1,i - 1){
            int x;
            scanf("%d",&x);
            if ( x ) e[j][i] = 1;
            else e[i][j] = 1;
        }
    }
    rep(i,1,n) if ( !dfn[i] ) dfs(i);
    solve();
}

POI 2018

题目不是很难,但是细节真的很多。要完全自己全部理清楚需要细致的思维。
从上午10点到12点,下午16点到晚上19点只写了4道题,效率太低了!

2019.3.13

5103: [POI2018]Różnorodność

Description
给定一个n行m列的矩阵,请对于每个长宽均为k的连续子正方形,统计里面出现过的数值的种类数。
Input
第一行包含三个正整数n,m,k(n,m<=3000,k<=min(n,m))。
接下来n行,每行m个正整数a[i]j,表示矩阵中每个位置的数值。

题解
分开考虑每个颜色,每一个点对一个K∗K的正方形有贡献,但同一种颜色的贡献至多为1。
从上到下扫描矩阵,我们需要维护一些正方形的进入和删除。
由于正方形边长固定,每次贡献实际产生变化的是一个区间。
用线段树支持前驱后继的查找即可确定产生变化的区间。
每处理完一行,用差分+前缀和统计本行的答案。(所有颜色一起扫描线,直接可以计算答案)
时间复杂度O(N∗M∗LogM)。

总结
关于二维的差分要想清楚,为了只统计一次,每个矩形只统计最靠左,然后是最靠上的。
然后发现每个点的贡献区域是一个下凸东西,这东西不能维护。
不能想当然认为直接差分就好!
直接用矩形面积并的模型。但因为边长相同可以简化

代码还没有写
听说bzoj卡常

【BZOJ5102】[POI2018]Prawnicy

Description
定义一个区间(l,r)的长度为r-l,空区间的长度为0。
给定数轴上n个区间,请选择其中恰好k个区间,使得交集的长度最大。
Input
第一行包含两个正整数n,k(1<=k<=n<=1000000),表示区间的数量。
接下来n行,每行两个正整数l,r(1<=l

题解
假如我们已经确定了最终区间的左端点L,那么我们选择的区间一定是左端点在L左边,且右端点最右的K个点。所以我们将所有区间按左端点排序,用小根堆维护左端点在左边,且右端点最大的K个点。每次用第K大值更新答案即可。

总结
这道题很简单,但是一开始把看错了,看成求并了----这个可以wqs二分?
求交的话就是固定一个端点统计。
这样最优解一定会被统计到

[POI2018]Powódź

Description
在地面上有一个水箱,它的俯视图被划分成了n行m列个方格,相邻两个方格之间有一堵厚度可以忽略不计的墙,水
箱与外界之间有一堵高度无穷大的墙,因此水不可能漏到外面。已知水箱内每个格子的高度都是[0,H]之间的整数
,请统计有多少可能的水位情况。因为答案可能很大,请对10^9+7取模输出。两个情况不同当且仅当存在至少一个
方格的水位在两个情况中不同。
Input
第一行包含三个正整数n,m,H(n*m<=500000,1<=H<=10^9)。
接下来n行,每行m-1个整数a[i]j,表示(i,j)和(i,j+1)之间的墙的高度。
接下来n-1行,每行m个整数b[i]j,表示(i,j)和(i+1,j)之间的墙的高度。

题解
按高度从小到大排序,每次加入相当于合并两个联通块。增加的这个高度对每个联通块来说块内的水位相同。合并后把各自的方案数乘起来(因为在水位<=当前高度时,两块互不干扰)
用并查集维护

【BZOJ5100】【POI2018】Plan metra

Description
有一棵n个点的无根树,每条边有一个正整数权值,表示长度,定义两点距离为在树上的最短路径的长度。
已知2到n-1每个点在树上与1和n的距离,请根据这些信息还原出这棵树。
Input
第一行包含一个正整数n(2<=n<=500000),表示点数。
第二行包含n-2个正整数d(1,2),d(1,3),…,d(1,n-1),分别表示每个点到1的距离。
第三行包含n-2个正整数d(n,2),d(n,3),…,d(n,n-1),分别表示每个点到n的距离。
输入数据保证1<=d<=1000000。

题解(来自cz_xuyixuan)
分别考虑1和N之间是否有边直接相连。
若有边相连,所有到1和N距离的差值的绝对值应该相等。
否则,到1和N距离的和的最小值就是1到N的距离,将这条链构造出来,将其它点逐一挂在上面即可。
时间复杂度O(N+D)。

总结:
一开始忘了判1-N的连边,一直WA。
然后为了简便直接开距离那么大的vector,忘了乘2.
调了很久,大概1个多小时,本来是非常简单的题,但是细节注意的很不好
一定要想清楚再写!
把代码贴上来警醒自己!

#include
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const int inf = 2e8;
const int N = 2e6 + 10;
const int maxn = 500020;
const ll mod = 1e9 + 7;

struct node{
	int next,to,w,from;
}e[maxn * 2];
int head[maxn],cnt;
int fa[maxn],dth[maxn];
int n,m;
pr dis[maxn];
vector <int> vec[N];

inline void adde(int x,int y,int w){
//	cout<
	if ( w <= 0 )return;
	e[++cnt].to = y;
	e[cnt].from = x;
	e[cnt].next = head[x];
	e[cnt].w = w;
	head[x] = cnt;
}
bool cmp(int x,int y){
	return (dis[x].fi + dis[x].se) < (dis[y].fi + dis[y].se);
}
void dfs(int x,int fa){
	fore(i,x){
		if ( e[i].to == fa ) continue;
		dth[e[i].to] = dth[x] + e[i].w;
		dfs(e[i].to,x);
	}
}
bool check(){
	rep(i,1,n) dth[i] = 0;
	dfs(1,0);
	rep(i,1,n) if ( dis[i].fi != dth[i] ) return 0;
	rep(i,1,n) dth[i] = 0;
	dfs(n,0);
	rep(i,1,n) if ( dis[i].se != dth[i] ) return 0;
	return 1;
}
bool check2(){
	int d = abs(dis[2].fi - dis[2].se);
	if ( !d ) return 0;
	rep(i,2,n - 1) if ( abs(dis[i].fi - dis[i].se) != d ) return 0;
	puts("TAK");
	printf("%d %d %d\n",1,n,d);
	rep(i,2,n - 1){
		if ( dis[i].fi < dis[i].se ) printf("%d %d %d\n",i,1,dis[i].fi);
		else printf("%d %d %d\n",i,n,dis[i].se);
	}
	return 1;
}
int main(){
//	freopen("input.txt","r",stdin);
	scanf("%d",&n);
	if ( n == 2 ){
		cout<<"TAK\n";
		cout<<"1 2 1\n";
		return 0;
	}
	rep(i,2,n - 1) scanf("%d",&dis[i].fi);
	rep(i,2,n - 1) scanf("%d",&dis[i].se);
	if ( check2() ){
		return 0;
	}
	m = inf;
	rep(i,2,n - 1) m = min(m,dis[i].fi + dis[i].se);
	dis[1] = mp(0,m) , dis[n] = mp(m,0);
	rep(i,1,n){
		int d = (dis[i].fi + dis[i].se - m) / 2;
		if ( dis[i].fi - d >= 0 ) vec[dis[i].fi - d].pb(i);
	}
	int last = 0,lastd = 0;
	rep(i,0,m){
		if ( !vec[i].size() ) continue;
		sort(vec[i].begin(),vec[i].end(),cmp);
//		cout<<" dist : "<
//		rvc(j,vec[i]) cout<
		if ( last ) adde(last,vec[i][0],dis[vec[i][0]].fi - lastd) , adde(vec[i][0],last,dis[vec[i][0]].fi - lastd);
		last = vec[i][0] , lastd = dis[vec[i][0]].fi;
		int id = 0;
		rep(j,1,vec[i].size() - 1){
			int w = ((dis[vec[i][j]].fi + dis[vec[i][j]].se) - (dis[vec[i][id]].fi + dis[vec[i][id]].se)) / 2;
			adde(vec[i][id],vec[i][j],w);
			adde(vec[i][j],vec[i][id],w);
		}
		vec[i].clear();
	}
	if ( check() ){
		puts("TAK");
		for (int i = 1 ; i <= cnt ; i += 2){
			printf("%d %d %d\n",e[i].from,e[i].to,e[i].w);
		}
	}
	else puts("NIE");
}
5099: [POI2018]Pionek

Description
在无限大的二维平面的原点(0,0)放置着一个棋子。你有n条可用的移动指令,每条指令可以用一个二维整数向量表
示。每条指令最多只能执行一次,但你可以随意更改它们的执行顺序。棋子可以重复经过同一个点,两条指令的方
向向量也可能相同。你的目标是让棋子最终离原点的欧几里得距离最远,请问这个最远距离是多少?
Input
第一行包含一个正整数n(n<=200000),表示指令条数。
接下来n行,每行两个整数x,y(|x|,|y|<=10000),表示你可以从(a,b)移动到(a+x,b+y)。

题解
这题没有想出来,连极角排序都没有想到,很不应该
对向量的性质很不敏感啊
确定了答案向量的方向,只会选投影在此方向为正的向量。
并且,选择的向量一定是一个连续的区间
那么,极角排序,twopointers扫一遍,使得当前指针和当前向量的夹角<180
注意扫描过程中要边扫边更新答案

总结
很多细节:
1. 极角排序的时候在坐标范围小的时候老老实实用atan2(预选计算好角度)
2. 要记得当r < i时更新指针
3. 边扫边计算答案
4. 直接用atan2算角度,非常方便,扫一圈以后+2pi即可
5. 最后先把0,0判掉
6. 如果用叉积判角度要注意共线的情况,先把同向共线去掉(如果用atan2不用)。反向共线要用点积辅助判。很麻烦
还是不知道我的按照象限极角排序为什么有问题

#include
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;

const int inf = 2e8;
const int N = 3e6 + 10;
const int maxn = 1000020;
const ll mod = 1e9 + 7;
const double eps = 1e-7;
const double pi = acos(-1.0);

struct point{
	int x,y,k;
	double ang;
	point operator + (point a){
		return (point){x + a.x,y + a.y,0,ang};
	}
}dt[maxn],dt2[maxn];
int n,tot;
ll ans;

inline int quadrant(point a){
	if ( a.x >= 0 && a.y > 0 ) return 1;
	if ( a.x < 0 && a.y >= 0 ) return 2;
	if ( a.x <= 0 && a.y < 0 ) return 3;
	return 4;
	//	if ( a.x > 0 && a.y <= 0 ) return 4;
}
inline int det(point a,point b){
	return a.x * b.y - a.y * b.x;
}
inline int dot(point a,point b){
	return a.x * b.x + a.y * b.y;
}
inline int sgn(double x){
	if ( abs(x) < eps ) return 0;
	return x > 0 ? 1 : -1;
}
bool cmp(point a,point b){
//	int ka = quadrant(a) , kb = quadrant(b);
//	if ( a.k == b.k ){
//		return det(a,b) > 0;
//	}
//	return a.k < b.k;
	return a.ang < b.ang;
}
int main(){
//	freopen("input.txt","r",stdin);
	scanf("%d",&n);
	rep(i,1,n){
	   	scanf("%d %d",&dt[i].x,&dt[i].y),dt[i].k = quadrant(dt[i]),dt[i].ang = atan2(dt[i].y,dt[i].x);
		if ( !dt[i].x && !dt[i].y ){ i--; n--; }
	}
	sort(dt + 1,dt + n + 1,cmp);	
//	rep(i,1,n) cout<
/*	rep(i,1,n){
		if ( tot && det(dt[i],dt2[tot]) == 0 && dot(dt[i],dt2[tot]) > 0 ) dt2[tot] = dt[i] + dt2[tot];
		else dt2[++tot] = dt[i];
	}*/
//	rep(i,1,tot) dt[i] = dt2[i];
//	n = tot;
	rep(i,1,n) dt[i + n] = dt[i] , dt[i + n].ang += pi * 2;
	int r = 1; ll sx = dt[1].x , sy = dt[1].y;
	rep(i,1,n){
		if ( r < i ){
			sx = dt[i].x , sy = dt[i].y , r = i;
		}
		ans = max(ans,(ll)sx * sx + (ll)sy*sy);
		//(det(dt[i],dt[r + 1]) > 0 || (det(dt[i],dt[r + 1]) == 0 && dot(dt[i],dt[r + 1] ) < 0))
		while ( r < n + i - 1 && sgn(dt[r + 1].ang - dt[i].ang - pi) <= 0 ) ++r , sx += dt[r].x , sy += dt[r].y, 	ans = max(ans,(ll)sx * sx + (ll)sy*sy);;
		//ans = max(ans,(ll)sx * sx + (ll)sy*sy);
		sx -= dt[i].x , sy -= dt[i].y;
	}
	cout<<ans<<endl;
}

你可能感兴趣的:(个人刷题,POI)