• 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,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
    ",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
    ")
    #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
    ");
        else 
            printf("%lld
    ",dis[id(zhongx,zhongy)]);
    }
    View Code

     柱状图

    模拟退火板子题,非常板子

    模拟退火最吼了

    即使是板子我也要说说

    首先关于

        nth_element(s+1,s+mid,s+n+1);

    为什么要求出中位数,

    前置知识

    坐标轴上有很多点,点与点之间有一个距离,你将所有点移到同一个点最小花费

    显然是移到中位数的点

    那么应用到这个题呢?

    你可以将题目要求转化,首先全部移到同一水平线上,然后再加出值

    比它高的降低,比它矮的升高,换成坐标轴我们就用到了中位数

    然后

    if(tmpans<nowans||exp(-D/T)*RAND_MAX>rand())

    为什么是

    exp(-D/T)*RAND_MAX>rand()

    不是

    exp(D/T)*RAND_MAX>rand()

    问的好啊!

    首先我们如果当前解优那么你会通过tmpans<nowans跳过

    然后如果当前解不优D一定是负的,如果D为负的那么D越小-D越大.D小代表当前解非常差,让它变成其他解概率更大

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define A 1010101
    const double eps=1e-5;
    const double delta=0.98;
    const double fj=1;
    ll n,ans=0x7ffffffffffffff;
    ll s[A],h[A];
    ll check(ll pos){
        for(ll j=1;j<=n;j++)
            s[j]=h[j]+abs(pos-j);
        ll mid=n+1>>1;
        nth_element(s+1,s+mid,s+n+1);
        ll val=s[mid];ll tot=0;
        if(val<max(pos,n-pos+1))
            val=max(pos,n-pos+1);
        for(ll i=1;i<=n;i++)
            tot+=abs(s[i]-val);
        return tot;
    }
    int main(){
        srand(time(0));
        scanf("%lld",&n);
        for(ll i=1;i<=n;i++){
            scanf("%lld",&h[i]);
        }
        double T=1000;
        ll now=(n+1)>>1;
        ll nowans=check(now);
        while(T>eps){
            ll tmp=now+(2ll*rand()-RAND_MAX)*T*0.000001;
            tmp=(tmp%n+n-1)%n+1;
            ll tmpans=check(tmp),D=tmpans-nowans;
            if(tmpans<nowans||exp(-D/T)*RAND_MAX>rand())
                nowans=tmpans,now=tmp;
            if(tmpans<ans) ans=tmpans;
            T*=delta;
        }
        printf("%lld
    ",ans);
    }
    View Code
    我已没有下降的余地
  • 相关阅读:
    基于JSP+SERVLET的新闻发布系统(三)
    linux date
    试论知识工作者的任务分析
    SRM 577 Div II Level Two: EllysRoomAssignmentsDiv2
    UNIX环境高级编程——TCP/IP网络编程
    是时候抛弃web.xml了?
    使用Spring Boot Actuator、Jolokia和Grafana实现准实时监控--转
    spring-security-oauth2注解详解
    一张图了解javaJwt
    nginx假死导致的问题回顾
  • 原文地址:https://www.cnblogs.com/znsbc-13/p/11319578.html
Copyright © 2020-2023  润新知