昨天学长问我了一个今日头条的题目,我看着有点像线段树+二分,今早上就尝试了一下,但是还没交,所以不知道对不对,题意大概给定数列a,b求所有区间当中有多少区间满足a的最大值小于b的最小值,暴力枚举每个区间一定超时,就想到了n^log^log,也就是线段树+二分,用线段树处理最大值和最小值的查询,用二分查找最大值变更的位置,因为有个性质就是,区间越大,最大值只可能越大,而最小值只可能越小,我们只需要知道这些变更的位置,然后枚举就行了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#define maxn 400010
using namespace std;
struct xtree{
long long l,r;
long long maxx,minn;
long long mid(){
return (l+r)/2;
}
}atree[maxn],btree[maxn];
struct point{
long long x;
long long y;
};
long long a[100010],b[100010];
vector<point>A[100010];
vector<point>B[100010];
void apushup(long long id){
atree[id].maxx=max(atree[id*2].maxx,atree[id*2+1].maxx);
}
void bpushup(long long id){
btree[id].minn=min(btree[id*2].minn,btree[id*2+1].minn);
}
void abuild(long long id,long long l,long long r){
atree[id].l=l;
atree[id].r=r;
if (l==r){
atree[id].maxx=a[l];
return ;
}
long long mid=atree[id].mid();
abuild(id*2,l,mid);
abuild(id*2+1,mid+1,r);
apushup(id);
}
void bbuild(long long id,long long l,long long r){
btree[id].l=l;
btree[id].r=r;
if (l==r){
btree[id].minn=b[l];
return ;
}
long long mid=btree[id].mid();
bbuild(id*2,l,mid);
bbuild(id*2+1,mid+1,r);
bpushup(id);
}
long long aquery(long long id,long long l,long long r){
if (atree[id].l>=l&&atree[id].r<=r){
return atree[id].maxx;
}
long long mid=atree[id].mid();
if (r<=mid){
return aquery(id*2,l,r);
}
else if (l>mid){
return aquery(id*2+1,l,r);
}
else {
return max(aquery(id*2,l,mid),aquery(id*2+1,mid+1,r));
}
}
long long bquery(long long id,long long l,long long r){
if (btree[id].l>=l&&btree[id].r<=r){
return btree[id].minn;
}
long long mid=btree[id].mid();
if (r<=mid){
return bquery(id*2,l,r);
}
else if (l>mid){
return bquery(id*2+1,l,r);
}
else {
return min(bquery(id*2,l,mid),bquery(id*2+1,mid+1,r));
}
}
long long solve(long long n){
long long i,j,k;
long long ans=0;
for (i=1;i<=n;i++){
long long x=A[i].size();
long long y=B[i].size();
k=0;
long long apla,bpla,amax,bmin;
long long lasta=i;
bpla=B[i][k].x;
bmin=B[i][k].y;
for (j=0;j<x;j++){
apla=A[i][j].x;
amax=A[i][j].y;
if (amax<bmin){
if (apla<=bpla){
ans+=apla-lasta+1;
lasta=apla+1;
}
else {
ans+=bpla-lasta+1;
lasta=bpla;
j--;
k++;
if (k<y){
bpla=B[i][k].x;
bmin=B[i][k].y;
}
}
}
else {
break;
}
}
}
return ans;
}
int main(){
long long n;
long long i,j;
while (scanf("%lld",&n)!=EOF){
for (i=1;i<=n;i++){
A[i].clear();
B[i].clear();
}
for (i=1;i<=n;i++)scanf("%lld",&a[i]);
abuild(1,1,n);
for (i=1;i<=n;i++)scanf("%lld",&b[i]);
bbuild(1,1,n);
for (i=1;i<=n;i++){
for (j=i;j<=n;){
long long temp=a[j];
long long l=i,r=n;
long long ans;
while (l<=r){
long long mid=(l+r)/2;
long long fun=aquery(1,i,mid);
if (fun<=temp){
l=mid+1;
ans=mid;
}
else r=mid-1;
}
point p;
p.x=ans;
p.y=temp;
A[i].push_back(p);
j=ans+1;
}
}
for (i=1;i<=n;i++){
for (j=i;j<=n;){
long long temp=b[j];
long long l=i,r=n;
long long ans;
while (l<=r){
long long mid=(l+r)/2;
long long fun=bquery(1,i,mid);
if (fun>=temp){
l=mid+1;
ans=mid;
}
else r=mid-1;
}
point p;
p.x=ans;
p.y=temp;
B[i].push_back(p);
j=ans+1;
}
}
long long ans=solve(n);
cout<<ans<<endl;
}
}
/*
3
1 2 3
3 3 3
5
1 2 3 4 5
5 5 5 5 5
6
1 1 2 2 3 3
3 3 2 2 1 1
10
1 1 1 1 1 3 3 3 3 3
2 2 2 3 3 3 1 1 1 1
*/
POJ 2187 Beauty Contest(凸包:最远点对距离):
让求任意两点的距离的最大值,这个值一定出现在凸包上,搞出来凸包然后暴力枚举就行了
POJ 1113 Wall(凸包应用):
让用一个图形去包裹另一个多边形(未指定凹凸),,使得周长最小,且距离大于等于L
这时候,计算一个凸包的周长+半径为L的周长即可
突然想起来还有尺取法这个好东西,这样应该就不怕变态样例了:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#define maxn 400010
using namespace std;
struct xtree{
long long l,r;
long long maxx,minn;
long long mid(){
return (l+r)/2;
}
}atree[maxn],btree[maxn];
struct point{
long long x;
long long y;
};
long long a[100010],b[100010];
vector<point>A[100010];
vector<point>B[100010];
void apushup(long long id){
atree[id].maxx=max(atree[id*2].maxx,atree[id*2+1].maxx);
}
void bpushup(long long id){
btree[id].minn=min(btree[id*2].minn,btree[id*2+1].minn);
}
void abuild(long long id,long long l,long long r){
atree[id].l=l;
atree[id].r=r;
if (l==r){
atree[id].maxx=a[l];
return ;
}
long long mid=atree[id].mid();
abuild(id*2,l,mid);
abuild(id*2+1,mid+1,r);
apushup(id);
}
void bbuild(long long id,long long l,long long r){
btree[id].l=l;
btree[id].r=r;
if (l==r){
btree[id].minn=b[l];
return ;
}
long long mid=btree[id].mid();
bbuild(id*2,l,mid);
bbuild(id*2+1,mid+1,r);
bpushup(id);
}
long long aquery(long long id,long long l,long long r){
if (atree[id].l>=l&&atree[id].r<=r){
return atree[id].maxx;
}
long long mid=atree[id].mid();
if (r<=mid){
return aquery(id*2,l,r);
}
else if (l>mid){
return aquery(id*2+1,l,r);
}
else {
return max(aquery(id*2,l,mid),aquery(id*2+1,mid+1,r));
}
}
long long bquery(long long id,long long l,long long r){
if (btree[id].l>=l&&btree[id].r<=r){
return btree[id].minn;
}
long long mid=btree[id].mid();
if (r<=mid){
return bquery(id*2,l,r);
}
else if (l>mid){
return bquery(id*2+1,l,r);
}
else {
return min(bquery(id*2,l,mid),bquery(id*2+1,mid+1,r));
}
}
long long solve(long long n){
long long i,j,k;
long long ans=0;
long long s=1;
long long maxx=a[1];
long long minn=b[1];
for (i=1;i<=n;i++){
if (a[i]>maxx){
maxx=a[i];
}
if (b[i]<minn){
minn=b[i];
}
if (minn<=maxx){
ans+=i-1-s+1;
while (minn<=maxx){
s++;
if (s>i)break;
maxx=aquery(1,s,i);
minn=bquery(1,s,i);
ans+=i-1-s+1;
}
}
}
ans+=n-s+1;
return ans;
}
int main(){
long long n;
long long i,j;
while (scanf("%lld",&n)!=EOF){
for (i=1;i<=n;i++){
A[i].clear();
B[i].clear();
}
for (i=1;i<=n;i++)scanf("%lld",&a[i]);
abuild(1,1,n);
for (i=1;i<=n;i++)scanf("%lld",&b[i]);
bbuild(1,1,n);
long long ans=solve(n);
cout<<ans<<endl;
}
}
/*
3
1 2 3
3 3 3
5
1 2 3 4 5
5 5 5 5 5
6
1 1 2 2 3 3
3 3 2 2 1 1
10
1 1 1 1 1 3 3 3 3 3
2 2 2 3 3 3 1 1 1 1
*/
下午比赛暴1了,不想多说,我就是个傻子
快速幂之后我居然用原矩阵计算的结果,一直没检查出来,就怎么一点点错误,改了立马a了,和题解一样的思路,改了两个多小时愣是没发现,完蛋。
样例太小也是个坑。
#include<iostream>
#include<cstring>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<cstdio>
#define maxn 1000010
#define mo 1000000007
using namespace std;
struct matrix{
long long a[11][11],n;
matrix(long long f,long long size){
long long i;
n=size;
memset (a,0,sizeof(a));
if (f==0)return ;
for (i=1;i<=n;i++)a[i][i]=1;
}
matrix operator*(const matrix&fun)const{
matrix ans(0,n);
long long i,j,k;
for (i=1;i<=n;i++){
for (k=1;k<=n;k++){
if (a[i][k])for (j=1;j<=n;j++){
ans.a[i][j]=(ans.a[i][j]+a[i][k]*fun.a[k][j]%mo+mo)%mo;
}
}
}
return ans;
}
matrix qpow(long long x)const{
int i,j;
matrix ans(1,n);
matrix tmp=(*this);
while (x){
if (x&1)ans=ans*tmp;
tmp=tmp*tmp;
x>>=1;
}
return ans;
}
};
long long a[maxn];
long long b[3];
int main(){
long long t;
long long A,B,c,d,p,n;
long long i,j;
scanf("%lld",&t);
while (t--){
scanf("%lld%lld%lld%lld%lld%lld",&A,&B,&c,&d,&p,&n);
a[1]=A;
a[2]=B;
long long temp=min(n,(long long)1000000);
for (i=3;i<=temp;i++){
a[i]=(c*a[i-2]%mo+d*a[i-1]%mo+p/i+mo)%mo;
}
if (n==temp)printf("%lld\n",a[n]);
else {
temp=p/(p/temp+1);
long long fun;
b[1]=a[temp+1];
b[2]=a[temp+2];
while (1){
fun=p/temp-1;
if (fun){
fun=p/fun;
long long e=min(n,fun);
if (e-temp>2){
matrix x(0,3);
x.a[1][1]=d;
x.a[1][2]=c;
x.a[1][3]=p/fun;
x.a[2][1]=1;
x.a[3][3]=1;
matrix ans=x.qpow(e-temp-3);
long long ans1=(ans.a[1][1]*b[2]%mo+ans.a[1][2]*b[1]%mo+ans.a[1][3]+mo)%mo;
matrix y(0,3);
y.a[1][1]=d;
y.a[1][2]=c;
y.a[1][3]=p/fun;
y.a[2][1]=1;
y.a[3][3]=1;
ans=y.qpow(e-temp-2);
long long ans2=(ans.a[1][1]*b[2]%mo+ans.a[1][2]*b[1]%mo+ans.a[1][3]+mo)%mo;
if (e==n){
printf("%lld\n",(ans2+mo)%mo);
break;
}
else {
b[1]=(c*ans1%mo+d*ans2%mo+p/(e+1)+mo)%mo;
b[2]=(c*ans2%mo+d*b[1]%mo+p/(e+2)+mo)%mo;
}
temp=e;
}
else {
if (e-temp==1&&n==e){
printf("%lld\n",b[1]);
}
else {
printf("%lld\n",b[2]);
}
}
}
else {
long long e=n;
matrix x(0,3);
x.a[1][1]=d;
x.a[1][2]=c;
x.a[1][3]=0;
x.a[2][1]=1;
x.a[3][3]=1;
matrix ans=x.qpow(e-temp-2);
long long ans1=(ans.a[1][1]*b[2]%mo+ans.a[1][2]*b[1]%mo+ans.a[1][3])%mo;
printf("%lld\n",(ans1+mo)%mo);
break;
}
}
}
}
}
/*
5
1 1 2 1 1000000000 1000000000
1 1 2 1 1000000 1000000000
1 1 2 1 1000000000 1000000
1 1 2 1 1000000000 1001000
1 1 2 1 1000000000 1000000
5
1 1 2 1 1000000000 1001000
1 1 2 1 1000000000 999999
*/