NOIP模拟测试14「旋转子段·走格子·柱状图」

旋转子段

连60分都没想,考试一直肝t3,t2,没想到t1最简单

我一直以为t1很难,看了题解发现也就那样

题解

性质1

一个包含a[i]旋转区间值域范围最多为min(a[i],i)----max(a[i],i)

感性理解

举个例子,例如3 7 1 4 5 6 2

这个子段包含a[2]的最大为值域范围2----7

具体证明我不会

性质2

翻转后满足固定点对的点满足

a[i]+i==a[j]+j

证明

因为翻转之前a[i]==j&&a[j]==i才满足翻转之后都构成点对

移项得到a[i]+i==a[j]+j

有了这两条性质我们可以得到一个$n^2$算法

for(ll i=1;i<=n;i++){
        tot=0;
        for(ll j=min(i,a[i]);j<=max(i,a[i]);j++)
            if(a[j]+j==a[i]+i)
                tot++;
}

得到tot最大值输出即可

70分代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 1010101
ll f[A],a[A],sum[A];
ll n,ans=-1,tot=0;
vector<ll>too[501010];
int main(){
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        sum[i]=sum[i-1];
        if(a[i]==i) sum[i]++;
    }
    for(ll i=1;i<=n;i++){
        tot=0;
        for(ll j=min(i,a[i]);j<=max(i,a[i]);j++){
            if(a[j]+j==a[i]+i){
                tot++;
            }
        }
//        printf("n=%lld max=%lld min=%lld i=%lld tot=%lld\n",n,max(i,a[i]),min(i,a[i]),i,tot);
        ans=max(tot+sum[n]-sum[max(i,a[i])]+sum[min(i,a[i])-1],ans);
    }
    printf("%lld\n",ans);
}
View Code

100分

莫队维护一下询问,需要卡常,卡常到自闭,fh卡常大师

分块0.53最优

#include<bits/stdc++.h>
using namespace std;
#define ll int
const int A=1010101,L=1<<20|1;
#define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++)
ll f[A],a[A],sum[A],tong[A],belong[A];
ll n,ans=-1,l=1,r=0,ou=0,block;
char buf[L],*S,*T;
struct moo{
    ll zhong,r,l,a;
    friend bool operator < (moo a,moo b){
        return ((belong[a.l]^belong[b.l]))?a.l<b.l:((belong[a.l]&1)?a.r<b.r:a.r>b.r);
    }
}mo[A];
inline ll read(){
    ll x=0;char c=getchar();
    while(!isdigit(c))c=getchar();
    while(isdigit(c))x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x;
}
int main(){
    n=read();
    block=pow(n,0.53);
    for(register ll i=1;i<=n;i++){
        a[i]=read();
        sum[i]=sum[i-1];
        if(!(a[i]^i)) sum[i]++;
        belong[i]=(i-1)/block+1;
    }
    for(register ll i=1;i<=n;i++){
        mo[i].zhong=i;
        mo[i].r=max(i,a[i]);
        mo[i].l=min(i,a[i]);
        mo[i].a=a[i];
    }
    sort(mo+1,mo+n+1);
    for(register ll i=1;i<=n;i++){
        while(l>mo[i].l) tong[l-1+a[l-1]]++,l--;
        while(l<mo[i].l) tong[l+a[l]]--,l++;
        while(r>mo[i].r) tong[r+a[r]]--,r--;
        while(r<mo[i].r) tong[r+1+a[r+1]]++,r++;
        ans=max(tong[mo[i].zhong+mo[i].a]+sum[n]-sum[mo[i].r]+sum[mo[i].l-1],ans);
    }
    printf("%d",ans);
}
View Code

走格子

显然贪心有门走门不对一个稍简单的数据就可以卡掉你

7 8
########
##.F#..#
#...C..#
##..#..#
##.....#
#..#...#
########

那怎么办,只能走八个方向爆搜吗?

显然可以最短路!

从每个墙开始搜直接得到每个点到墙最短距离,然后每两相邻点之间建边,点墙之间建边

例如               (墙)

       |

      50

            |

(墙)-----21------Q-------------500000000-------(墙)

      |

      |

      600

      |

      (墙)

我们只需要将Q与四个墙方向边权都设置为21即可.(例如可以在2打传送门  然后在4打传送门从2传送到4,那么所有最小代价都为21)

很简单对不对,直接跑最短路就行了

保证最短路会松弛掉一些不可行解

例如

      (墙)

        |

       50

     (墙)|

(墙)------21--Q-------500000--(墙)

      |

      50

      |

     (终点)

向上走一步再打传送门会松弛掉21这条边

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define A 5010101
#define py printf("toot\n")
#define fr first
#define se second
#define mp(x,y) make_pair(x,y)
ll zh[610][610],top[610][610],low[610][610],zuo[610][610],you[610][610],bs[610][610],head[A],nxt[A],ver[A],edg[A],dis[A];
const ll nowx[5]={0,0,0,1,-1};
const ll nowy[5]={0,1,-1,0,0};
bool vis[A];
ll n,m,zhongx,zhongy,qix,qiy,ttt=0,tot=0;
deque<pair<ll,ll> >q,toot;
char s[610][610];
ll id(ll i,ll j){
    return (i-1)*m+j;
}
void add(ll x,ll y,ll z){
    nxt[++tot]=head[x],head[x]=tot,ver[tot]=y,edg[tot]=z;return ;
}
void ins(ll x,ll y,ll d){
    if(!bs[x][y]&&s[x][y]=='.'){
        bs[x][y]=d;
        q.push_back(mp(x,y));
    }
}
void bfs(){
    while(!q.empty()){
        ll kx=q.front().fr,ky=q.front().se;
        q.pop_front();
//        py;
        for(ll i=1;i<=4;i++){
            ins(kx+nowx[i],ky+nowy[i],bs[kx][ky]+1);
        }
    }
}
void init(){
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++){
            if(s[i][j]=='#') continue;
            if(s[i][j-1]=='#') zuo[i][j]=id(i,j);
            else zuo[i][j]=zuo[i][j-1];
            if(s[i-1][j]=='#') top[i][j]=id(i,j);
            else top[i][j]=top[i-1][j];
        }
    for(ll i=n;i>=1;i--)
        for(ll j=m;j>=1;j--){
            if(s[i][j]=='#') continue;
            if(s[i][j+1]=='#') you[i][j]=id(i,j);
            else you[i][j]=you[i][j+1];
            if(s[i+1][j]=='#') low[i][j]=id(i,j);
            else low[i][j]=low[i+1][j];
        }
}
void addb(){
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++){
            if(s[i][j]=='#') continue;
            ll d=id(i,j);
            if(s[i+1][j]=='.') add(d,id(i+1,j),1),add(id(i+1,j),d,1);
            if(s[i][j+1]=='.') add(d,id(i,j+1),1),add(id(i,j+1),d,1);
            if(zuo[i][j]!=d)add(d,zuo[i][j],bs[i][j]);
            if(you[i][j]!=d)add(d,you[i][j],bs[i][j]);
            if(top[i][j]!=d)add(d,top[i][j],bs[i][j]);
            if(low[i][j]!=d)add(d,low[i][j],bs[i][j]);
        }
}
void spfa(ll o){
    vis[o]=1;
    memset(dis,0x7f,sizeof(dis));
    dis[o]=0;
    deque<ll> toot;
    toot.push_back(o);
    while(!toot.empty()){
        
        ll x=toot.front();
        toot.pop_front();
        for(ll i=head[x];i;i=nxt[i]){
            ll y=ver[i];
            if(dis[y]>dis[x]+edg[i]){
                dis[y]=dis[x]+edg[i];
                if(!vis[y]){
                    vis[y]=1;
                    toot.push_back(y);
                }
            }
        }
        vis[x]=0;
    }
}
int main(){
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++){
        scanf("%s",s[i]+1);
        for(ll j=1;j<=m;j++){
            if(s[i][j]=='#'){
                q.push_back(mp(i,j));
            }
            else 
            if(s[i][j]=='C'){
                s[i][j]='.';
                qix=i;
                qiy=j;
            }
            if(s[i][j]=='F'){
                s[i][j]='.';
                zhongx=i;
                zhongy=j;
            }
        }
    }
    bfs(),init(),addb(),spfa(id(qix,qiy));
    if(dis[id(zhongx,zhongy)]>=1202134)
        printf("no\n");
    else 
        printf("%lld\n",dis[id(zhongx,zhongy)]);
}
View Code

猜你喜欢

转载自www.cnblogs.com/znsbc-13/p/11319578.html