2018年8月13日暑假訓練日記
昨天學長問我了一個今日頭條的題目,我看著有點像線段樹+二分,今早上就嘗試了一下,但是還沒交,所以不知道對不對,題意大概給定數列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
*/