zoukankan      html  css  js  c++  java
  • NOIP模拟测试14

    考完19了再写14,我也是够咕的。

    14的题很好,也充分暴露了我的问题。

    T1是个分析性质推结论的题

    对于区间[L,R],不妨设a[L]!=a[R],那么两个端点对答案没有贡献,也就是[L+1,R],[L,R-1]都是符合题意的区间。

    即 最优的区间的两个端点一定相等

    然后把每个数的位置和大小作为区间的两端点,统计答案即可。

     1 #include<bits/stdc++.h>
     2 #define F(n) for(int i=1;i<=n;i++)
     3 int a[500005],sum[500005],n,ans;
     4 std::vector< std::pair<int,int> >k[500005<<1];
     5 int main(){
     6     scanf("%d",&n);
     7     F(n)scanf("%d",&a[i]),sum[i]=sum[i-1]+(a[i]==i);ans=sum[n];
     8     F(n)k[a[i]+i].push_back(std::make_pair(std::min(i,a[i]),std::max(i,a[i])));
     9     F((n<<1))sort(k[i].begin(),k[i].end());
    10     F((n<<1))
    11         for(int t=k[i].size(),j=t-1,last=0;j>=0;j--,last++)
    12             ans=std::max(ans,last+1+sum[k[i][j].first-1]+sum[n]-sum[k[i][j].second]);
    13     std::cout<<ans;
    14 }
    View Code

    T2走格子

    关键在于如何将题目抽象成图论模型,而不是只一味的搜索。

    这道题没有太多的限制,只有移动到每个格子的距离的不同。

    因此直接建边,跑dijstra即可

     1 #include<bits/stdc++.h>
     2 #define MAXN 505
     3 using namespace std;
     4 const int h[5]={0,1,-1,0,0},l[5]={0,0,0,1,-1};
     5 int mp[MAXN][MAXN],endx,endy,n,m,tot=0;
     6 priority_queue<pair<int,int> >Q;
     7 vector<int>zh[MAXN],zl[MAXN];
     8 bool vst[MAXN*MAXN];
     9 int ans=0x7f7f7f7f,stax,stay;
    10 int p[MAXN][MAXN],d[MAXN*MAXN],nxt[MAXN*MAXN*100],val[MAXN*MAXN*100],to[MAXN*MAXN*100],cnt,head[MAXN*MAXN];
    11 void add(int u,int v,int w)
    12 {
    13     to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;val[cnt]=w;
    14     return ;
    15 }
    16 int dijstra()
    17 {
    18     memset(d,0x3f,sizeof(d));d[p[stax][stay]]=0;
    19     Q.push(make_pair(0,p[stax][stay]));
    20     while(Q.size())
    21     {
    22         int k=Q.top().second;Q.pop();
    23         if(k==p[endx][endy])return d[k];
    24         if(vst[k])continue;
    25         vst[k]=1;
    26         for(int i=head[k];i;i=nxt[i])
    27         {
    28             int y=to[i];
    29             if(d[y]>d[k]+val[i])
    30             {
    31                 d[y]=d[k]+val[i];
    32                 Q.push(make_pair(-d[y],y));
    33             }
    34         }
    35     }
    36     return 0x7f7f7f7f;
    37 }
    38 int main()
    39 {
    40     scanf("%d%d",&n,&m);
    41     for(int i=1;i<=n;i++)
    42     {
    43         for(int j=1;j<=m;j++)
    44         {
    45             p[i][j]=++tot;
    46             char c=getchar();
    47             while(c!='C'&&c!='F'&&c!='.'&&c!='#')c=getchar();
    48             if(c=='C')stax=i,stay=j,mp[i][j]=1;
    49             else if(c=='F')endx=i,endy=j,mp[i][j]=1;
    50             else if(c=='.')mp[i][j]=1;
    51             else mp[i][j]=0;
    52         }
    53     }
    54     for(int i=1;i<=n;i++)
    55         for(int j=1;j<=m;j++)
    56             if(!mp[i][j])zh[i].push_back(j);
    57     for(int j=1;j<=m;j++)
    58         for(int i=1;i<=n;i++)
    59             if(!mp[i][j])zl[j].push_back(i);
    60     for(int i=1;i<=n;i++)
    61         for(int j=1;j<=m;j++)
    62         {
    63             if(!mp[i][j])continue;
    64             if(i^1&&mp[i-1][j])add(p[i][j],p[i-1][j],1);
    65             if(i^n&&mp[i+1][j])add(p[i][j],p[i+1][j],1);
    66             if(j^1&&mp[i][j-1])add(p[i][j],p[i][j-1],1);
    67             if(j^m&&mp[i][j+1])add(p[i][j],p[i][j+1],1);
    68             int up=*(--lower_bound(zl[j].begin(),zl[j].end(),i));
    69             int down=*(lower_bound(zl[j].begin(),zl[j].end(),i));
    70             int lef=*(--lower_bound(zh[i].begin(),zh[i].end(),j));
    71             int rig=*(lower_bound(zh[i].begin(),zh[i].end(),j));
    72             int dis=min(i-up,min(down-i,min(j-lef,rig-j)));
    73             add(p[i][j],p[up+1][j],dis);
    74             add(p[i][j],p[down-1][j],dis);
    75             add(p[i][j],p[i][lef+1],dis);
    76             add(p[i][j],p[i][rig-1],dis);
    77         }
    78     ans=dijstra();
    79     if(ans==0x7f7f7f7f)cout<<"no"<<endl;
    80     else cout<<ans<<endl;
    81     return 0;
    82 }
    View Code

    T3柱状图  好题标记

    这道题考察的是三分。

    观察一下可知对于某一位置来说,其高度大小与最终答案的关系是单谷的。

    (当你得到一个最优答案的时候,如果变大会使其余的柱子在原基础上再上升一个,反之亦然)

    于是60分做法诞生:

    枚举位置,三分高度,统计答案   O(n^2logn)

     1 #include<bits/stdc++.h>
     2 #define MAXN 100005
     3 #define int long long
     4 #define F(x) for(int i=1;i<=n;i++)
     5 #define re register
     6 #define min(a,b) (a)<(b)?(a):(b)
     7 using namespace std;
     8 int a[MAXN],now,n,maxn;
     9 inline int Get(int h)
    10 {
    11     int ans=abs(h-a[now]);
    12     F(n)
    13     {
    14         if(i==now)continue;
    15         if(h-abs(i-now)<=0)return 0x7f7f7f7f7f7f7ff;
    16         ans+=abs(a[i]-(h-abs(i-now)));
    17     }
    18     return ans;
    19 }
    20 inline int San_fen()
    21 {
    22     int l=now,r=maxn*2;
    23     while(l+2<r)
    24     {
    25         int lmid=l+(r-l)/3;
    26         int rmid=r-(r-l)/3;
    27         if(Get(lmid)<Get(rmid))r=rmid;
    28         else l=lmid;
    29     }
    30     return min(Get(l),min(Get(l+1),Get(l+2)));
    31 }
    32 signed main()
    33 {
    34     re int ans=0x7f7f7f7f7f7f7ff;
    35     scanf("%lld",&n);
    36     F(n)scanf("%lld",&a[i]),maxn=max(maxn,a[i]);
    37     for(now=1;now<=n;now++)
    38         ans=min(ans,San_fen());
    39     cout<<ans<<endl;
    40     return 0;
    41 }
    View Code

    考虑优化,对于统计答案,我们分情况讨论一下

    (讨论个毛线)详情见这里

    主要说一下skyh的垃圾退火(雾)

    模拟退火是一个特别神(kan)奇(lian)的算法。

    是这样的:

    根据物理学常识我们可以知道,物体内能越小越稳定。

    所谓的模拟退火,就是模拟这个过程。

    1.设置初始温度T0

    2.找出下一个目标位置

    3.尝试用新的答案更新旧的答案

    4.降温

    是不是一脸蒙蔽?

    详细来说:

     1 while(T>eps)                                                          //终止边界
     2 {
     3     tmp=now+(rand()*2ll-RAND_MAX)*T*0.000001;                         //温度越高,变化越大
     4     if(T<1.0)tmp=max(tmp,1ll),tmp=min(tmp,n);                         //当温度小于一定程度的时候,让下一个位置尽量小地变化
     5     else tmp=(tmp%n+n)%n+1;                                           //让下一个位置在要求的范围内
     6     tmpans=calc(tmp);D=-fabs(tmpans-nowans);                          //找到新的解
     7     if(tmpans<nowans||exp(D/T)*RAND_MAX>rand())nowans=tmpans,now=tmp; //根据概率确定答案是否改变
     8     if(tmpans<ans)ans=tmpans;                                         //更新最终的答案
     9     T*=0.975;                                                         //降温
    10 }

    根据前人的经验,这个更新的概率是exp(D/T)(D是变化量绝对值的相反数,T是当前温度)

    最后附上完整代码

     1 #include<bits/stdc++.h>
     2 #define MAXN 100005
     3 #define int long long 
     4 using namespace std;
     5 int yx[MAXN],n,now;
     6 struct Bit{
     7     int tr[2][MAXN];
     8     void insert(int x,int val,int opt)
     9     {
    10         for(int i=x;i<=n;i+=i&-i)tr[0][i]+=val,tr[1][i]+=opt;
    11         return ;
    12     }
    13     pair<int,int> query(int x)
    14     {
    15         int num=0,ans=0;
    16         for(int i=x;i;i-=i&-i)num+=tr[1][i],ans+=tr[0][i];
    17         return make_pair(ans,num);
    18     }
    19 }T[2];
    20 int sa[MAXN],sb[MAXN],ap[MAXN],bp[MAXN],ans=0x7f7f7f7f7f7f7ff,maxa,a[MAXN],b[MAXN];
    21 inline int check(int x)
    22 {
    23     if(x<now||x<(n-now+1))return 0x7f7f7f7f7f7f7ff;
    24     int ans=abs(x-yx[now]);
    25     int num=upper_bound(a+1,a+n+1,x-now)-a-1;
    26     pair<int,int> w=T[0].query(num);
    27     ans+=abs(w.first-w.second*(x-now))+abs(sa[now-1]-w.first-(now-1-w.second)*(x-now));
    28     num=upper_bound(b+1,b+n+1,x+now)-b-1;
    29     w=T[1].query(num);
    30     ans+=abs(w.first-(now+x)*w.second)+abs(sb[n]-sb[now]-w.first-(n-now-w.second)*(now+x));
    31     return ans;
    32 }
    33 inline int san_fen()
    34 {
    35     int l=1,r=maxa*2;
    36     while(l+2<r)
    37     {
    38         int lmid=l+(r-l)/3,
    39             rmid=r-(r-l)/3;
    40         if(check(lmid)<check(rmid))r=rmid;
    41         else l=lmid;
    42     }
    43     return min(check(l+1),min(check(l+2),check(l)));
    44 }
    45 signed main()
    46 {
    47     cin>>n;
    48     for(int i=1;i<=n;i++)
    49     {
    50         scanf("%lld",&yx[i]);
    51         ap[i]=a[i]=yx[i]-i;
    52         bp[i]=b[i]=yx[i]+i;
    53         sa[i]=sa[i-1]+a[i];
    54         sb[i]=sb[i-1]+b[i];
    55         maxa=max(maxa,yx[i]);
    56     }
    57     sort(a+1,a+n+1);sort(b+1,b+n+1);
    58     for(int i=1;i<=n;i++)
    59     {
    60         ap[i]=lower_bound(a+1,a+n+1,ap[i])-a;
    61         bp[i]=lower_bound(b+1,b+n+1,bp[i])-b;
    62     }
    63     for(int i=1;i<=n;i++)T[1].insert(bp[i],yx[i]+i,1);
    64     for(now=1;now<=n;now++)
    65     {
    66         T[1].insert(bp[now],-(yx[now]+now),-1);
    67         ans=min(san_fen(),ans);
    68         T[0].insert(ap[now],yx[now]-now,1);
    69     }
    70     cout<<ans<<endl;
    71     return 0;
    72 }
    正解AC
     1 #include<bits/stdc++.h>
     2 #define MAXN 100005
     3 #define int long long
     4 #define re register
     5 using namespace std;
     6 double eps=1e-5,T=100,D;
     7 int mid,n,a[MAXN],b[MAXN];
     8 inline int calc(int x)
     9 {
    10     for(int i=1;i<=n;i++)b[i]=a[i]+abs(i-x);
    11     nth_element(b+1,b+mid,b+n+1);
    12     re int now=max(b[mid],max(x,n-x+1)),ans=0;
    13     for(int i=1;i<=n;i++)
    14     {
    15         if(now-abs(i-x)<=0)return 0x7f7f7f7f7f;
    16         ans+=abs(now-b[i]);
    17     }
    18     return ans;
    19 }
    20 signed main()
    21 {
    22     srand((unsigned)time(0));
    23     cin>>n;
    24     mid=(1+n)>>1;
    25     for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    26     int ans=0x7f7f7f7f7f7f;
    27     int now=(1+n>>1);
    28     int nowans=calc(now),tmp,tmpans;
    29     while(T>eps)
    30     {
    31         tmp=now+(rand()*2ll-RAND_MAX)*T*0.000001;
    32         if(T<1.0)tmp=max(tmp,1ll),tmp=min(tmp,n);
    33         else tmp=(tmp%n+n)%n+1;
    34         tmpans=calc(tmp);D=-fabs(tmpans-nowans);
    35         if(tmpans<nowans||exp(D/T)*RAND_MAX>rand())nowans=tmpans,now=tmp;
    36         if(tmpans<ans)ans=tmpans;
    37         T*=0.975;
    38     }
    39     cout<<ans<<endl;
    40     return 0;
    41 }
    退火AC

    模拟退火是一个特别优秀的算法,请不要针对算法,(尽管你可以针对脸某)。

  • 相关阅读:
    makefile
    xcode
    centos
    debug
    服务器开发
    socket
    xcode
    调用cpp库更基本
    nodejs cpp动态库
    html5图片裁剪法--
  • 原文地址:https://www.cnblogs.com/hzoi-kx/p/11343580.html
Copyright © 2011-2022 走看看