海亮02/19杂题
海亮02/19杂题
T1
题意
给定平面坐标系中 \(n\) 个点构成的点集 \(S\),保证三点不共线。称一个简单多边形是好的,当且仅当其顶点均为 \(S\) 中元素,且 \(S\) 中所有点均在多边形的边上或内部。
设 \(f\) 为好多边形中的顶点数最小值,求有多少个好多边形的顶点数 \(\le f + 1\)。
\(3\le n \le 2\times 10^3\)
题解
显然这个 \(f\) 就是凸包的点数。
又因为没有三点共线,所以 \(=f\) 的情况只有一个。
然后考虑怎么算 \(f+1\) 的合法情况。
发现其实就是看每个不在凸包上的点能不能加进凸包还能保证所有点都在里面。
我们设 \(u\) 是凸包上的一个点,\(i\) 是不在凸包上的一个点, \((u,i)\) 状态合法当且仅当 \(u\) 和下一个凸包上的点 \(v\),与点 \(i\) 组成的三角形中没有其他点。
然后发现对于每个不在凸包的点进行极角排序,然后如果有两个相邻(且编号相邻)的凸包点,那么 \(ans++\)。
记得开 \(long\space long\)!
代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
bool stmemory;
namespace Call_me_Eric{
typedef pair<int,int> pii;
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
const int maxn = 2e3 + 10;
int n, id[maxn];
pii p[maxn];
int operator * (pii a,pii b){return a.first * b.second - a.second * b.first;}
pii operator - (pii a,pii b){return make_pair(a.first - b.first,a.second - b.second);}
pair<pii,pii> tmp[maxn];
int stk[maxn], top;
int quad(pii u){
int x = u.first, y = u.second;
return (y < 0) << 1 | (x < 0) ^ (y < 0);
}
void main(){
n = read();for(int i = 1;i <= n;i++){p[i].first = read();p[i].second = read();}
sort(p + 1,p + 1 + n,[&](pii x,pii y){
return x.first != y.first ? x.first < y.first : x.second < y.second;
});
stk[++top] = 1;
for(int i = 2;i <= n;i++){
while(top >= 2 && (p[stk[top]] - p[stk[top - 1]]) * (p[i] - p[stk[top]]) <= 0)
id[stk[top--]] = 0;
id[i] = 1;stk[++top] = i;
}
int tot = top;
for(int i = n - 1;i;i--){
if(id[i])continue;
while(top > tot && (p[stk[top]] - p[stk[top - 1]]) * (p[i] - p[stk[top]]) <= 0)
id[stk[top--]] = 0;
id[i] = 1;stk[++top] = i;
}
top--;
for(int i = 1;i <= top;i++)id[stk[i]] = i;
// for(int i = 1;i <= n;i++)printf("i = %d,x = %d,y = %d,id = %d\n",i,p[i].first,p[i].second,id[i]);
int ans = 1;
for(int i = 1;i <= n;i++){
if(id[i])continue;
int t = 0;
for(int j = 1;j <= n;j++){
if(j == i)continue;
else tmp[++t] = make_pair(p[j] - p[i],make_pair(id[j],j));
}
sort(tmp + 1,tmp + n,[&](auto x,auto y){
return quad(x.first) < quad(y.first) || (quad(x.first) == quad(y.first) && (x.first * y.first > 0));
});
for(int j = 1;j < n;j++){
int y = (j + 1 == n) ? 1 : (j + 1);
int x = abs(tmp[y].second.first - tmp[j].second.first);
if(tmp[j].second.first && tmp[y].second.first
&& (x == 1 || x == top - 1))ans++;
}
// for(int j = 1;j < n;j++)
// printf("%d ",tmp[j].second.first);puts("");
// for(int j = 1;j < n;j++)
// printf("%d ",tmp[j].second.second);
// printf("\ni = %d,ans = %d\n",i,ans);
}
printf("%lld\n",ans);
return;
}
};
bool edmemory;
signed main(){
// freopen("tmp.in","r",stdin);
// freopen("tmp.out","w",stdout);
auto stclock = clock();
Call_me_Eric::main();
auto edclock = clock();
cerr << (&stmemory - &edmemory) / 1024.0 / 1024.0 << " Mib cost.\n";
cerr << (edclock - stclock) * 1.0 / CLOCKS_PER_SEC << " Sec cost.\n";
return 0;
}
T5
题意
设一个数组 \(a_{1,2,\dots,l}\) 是平衡的,当且仅当 \(\exists k\in[1,\frac{l - 1}{2}],\forall i\in[1,l - 2\times k],a_{i} + a_{i + 2\times k} = 2\times a_{i+k}\)。
现在给你一个数组 \(a\),你需要对 \(\forall l\in[1,n]\) 求出子序列 \(a_{1,2,\dots,l}\) 是不是平衡的。
\(n\le 2\times 10^6\)
题解
先想想最暴力的做法。
枚举 \(l,k\),然后对于区间 \([1,l]\),用 \(O(n)\) 的时间进行 \(check\)。总时间复杂度是 \(O(n^3)\) 的。
然后有一个神奇的 \(check\)。
你搞一下字符串 \(hash\),然后对于刚刚的 \(check\),你就可以直接在 \(hash\) 上进行加减。
然后你就可以 \(O(1)\) 的 \(check\) 了。(具体实现看代码)
但是还不够,怎么办?
我们发现,对于一个 \(k\),如果 \(l\) 不满足条件,那么 \(l+1\) 也一定不满足条件,于是就可以 \(O(n\log n)\) 的二分了,如果常数小的话可以直接过了。
但是还不够怎么办?
我们发现这里的 \(k\) 是 \(\exist k\),不是 \(\forall k\),于是可以维护一个右端点 \(l\)(不应该设 \(r\) 吗?不管了就这样吧。),不需要将这个指针向左移动。
然后就变成 \(O(n)\) 的了。
代码
#include<bits/stdc++.h>
using namespace std;
bool stmemory;
namespace Call_me_Eric{
inline int read(){
int x = 0, f = 1;char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1;ch = getchar();}
while(ch >= '0' && ch <= '9'){x = (x << 1) + (x << 3) + (ch ^ 48);ch = getchar();}
return x * f;
}
int readbase62(){
int x = 0;char ch = getchar();
while(!isdigit(ch) && !islower(ch) && !isupper(ch))ch = getchar();
while(isdigit(ch) || islower(ch) || isupper(ch)){
x = x * 62;
if(isupper(ch)){x += ch - 'A' + 36;}
if(islower(ch)){x += ch - 'a' + 10;}
if(isdigit(ch)){x += ch - '0' + 0;}
ch = getchar();
}
return x;
}
const int maxn = 2e6 + 10;
typedef unsigned long long ull;
int n, a[maxn];
ull hsh[2][maxn], pw[2][maxn], base[2] = {1145141ull,1919810ull};
ull gethash(int l,int r,int opt){return (hsh[opt][r] - hsh[opt][l - 1] * pw[opt][r - l + 1]);}
bool check(int l,int k){
if(2 * k + 1 > l)return 0;
return gethash(1,l - 2 * k,0) + gethash(2 * k + 1,l,0) == 2ull * gethash(k + 1,l - k,0)
&& gethash(1,l - 2 * k,1) + gethash(2 * k + 1,l,1) == 2ull * gethash(k + 1,l - k,1);
}
bool ans[maxn];
void main(){
n = read();for(int i = 1;i <= n;i++)a[i] = readbase62();
pw[0][0] = pw[1][0] = 1;
for(int i = 1;i <= n;i++){
pw[0][i] = pw[0][i - 1] * base[0];pw[1][i] = pw[1][i - 1] * base[1];
hsh[0][i] = hsh[0][i - 1] * base[0] + 1ull * a[i];
hsh[1][i] = hsh[1][i - 1] * base[1] + 1ull * a[i];
}
int i = 1;
for(int k = 1;k * 2 + 1 <= n;k++){
i = max(i,2 * k + 1);
while(i <= n && check(i,k)){ans[i++] = '1';}
}
for(int i = 1;i <= n;i++)putchar('0' + ans[i]);
putchar('\n');
return;
}
};
bool edmemory;
signed main(){
auto stclock = clock();
Call_me_Eric::main();
auto edclock = clock();
cerr << (&stmemory - &edmemory) / 1024.0 / 1024.0 << " Mib cost.\n";
cerr << (edclock - stclock) * 1.0 / CLOCKS_PER_SEC << " Sec cost.\n";
return 0;
}

浙公网安备 33010602011771号