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


    T1:旋转子段

      性质1:每个点有且只有一个旋转中心能使其旋转后变为固定点

      性质2:最优旋转子段的两端点至少有一个在旋转后成为固定点

      根据上述性质,可以发现,可能成为最优旋转子段的区间只有n个,枚举就好了

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<vector>
     7 #define ll long long
     8 using namespace std;
     9 const int MAXN=1000005,INF=0x3f3f3f3f;
    10 int n,v[MAXN],pos[MAXN],ans,sum[MAXN];
    11 vector<int> w[MAXN*2];
    12 int get_num(int l,int r,int x) {
    13     if(!w[x].size()) return 0;
    14     int tl=lower_bound(w[x].begin(),w[x].end(),l)-w[x].begin();
    15     int tr=upper_bound(w[x].begin(),w[x].end(),r)-w[x].begin();
    16     if(tl>tr) return 0;
    17     return tr-tl;
    18 }
    19 int main() {
    20     scanf("%d",&n);
    21     for(int i=1;i<=n;i++) {
    22         scanf("%d",&v[i]);
    23         pos[i]=v[i]+i-1;
    24         w[pos[i]].push_back(i);
    25         sum[i]=sum[i-1];
    26         if(v[i]==i) ++sum[i];
    27     }
    28     ans=sum[n];
    29     for(int i=1;i<=n;i++) {
    30         if(i==v[i]) continue;
    31         int tmp=0;
    32         int r=pos[i]-i+1,l=i;
    33         if(l>r) swap(l,r);
    34         tmp=get_num(l,r,pos[i]);
    35         tmp+=sum[l-1]+sum[n]-sum[r];
    36         ans=max(ans,tmp);
    37     }
    38     printf("%d
    ",ans);
    39     return 0;
    40 }
    t1 Code


     T2:走格子

      建图,对于每个空点,连出两种边

      一种表示向四个方向走一步

      即:向相邻的四个点连距离为1的边

      另一种表示向四个方向发射传送门,并走向四个方向中最近的墙,然后进行传送

      即:向四个方向墙的前一格连距离为最近的墙距离+1的边

      然后跑最短路即可

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<vector>
     7 #include<queue>
     8 #define ll long long
     9 using namespace std;
    10 const int MAXN=1005,INF=0x3f3f3f3f;
    11 int n,m,ans,bx,by,ex,ey;
    12 int dx[4]={0,-1,0,1},dy[4]={-1,0,1,0};
    13 char mp[MAXN][MAXN];
    14 bool vis[MAXN][MAXN];
    15 int to[MAXN*MAXN*8],nxt[MAXN*MAXN*8],dis[MAXN*MAXN*8],tot,h[MAXN*MAXN];
    16 void add(int x,int y,int z) {
    17     to[++tot]=y;
    18     nxt[tot]=h[x];
    19     dis[tot]=z;
    20     h[x]=tot;
    21 }
    22 bool noans() {
    23     queue<pair<int,int> > q;
    24     q.push(make_pair(bx,by));
    25     while(!q.empty()) {
    26         int x=q.front().first,y=q.front().second; q.pop();
    27         if(x==ex&&y==ey) return 0;
    28         for(int i=0;i<4;i++) {
    29             int nx=x+dx[i],ny=y+dy[i];
    30             if(mp[nx][ny]=='#') continue;
    31             if(vis[nx][ny]) continue;
    32             vis[nx][ny]=1;
    33             q.push(make_pair(nx,ny));
    34         }
    35     }
    36     return 1;
    37 }
    38 int mi[MAXN][MAXN],ver[MAXN][MAXN][4];
    39 int get_dis(int x,int y,int id) {
    40     int ret=0,lstx=x,lsty=y;
    41     while(mp[x][y]!='#') x=x+dx[id],y=y+dy[id],++ret;
    42     ver[lstx][lsty][id]=(x-dx[id]-1)*m+y-dy[id];
    43     return ret;
    44 }
    45 void build() {
    46     memset(mi,0x3f,sizeof(mi));
    47     for(int i=1;i<=n;i++)
    48         for(int j=1;j<=m;j++)
    49             if(mp[i][j]!='#') for(int k=0;k<4;k++)
    50                 mi[i][j]=min(mi[i][j],get_dis(i,j,k));
    51     for(int i=1;i<=n;i++)
    52         for(int j=1;j<=m;j++)
    53             if(mp[i][j]!='#') for(int k=0;k<4;k++)
    54                 if(ver[i][j][k]!=(i-1)*m+j)
    55                     add((i-1)*m+j,ver[i][j][k],mi[i][j]);
    56     for(int i=1;i<=n;i++)
    57         for(int j=1;j<=m;j++)
    58             if(mp[i][j]!='#') for(int k=0;k<4;k++)
    59                 if(mp[i+dx[k]][j+dy[k]]!='#')
    60                     add((i-1)*m+j,(i+dx[k]-1)*m+j+dy[k],1);
    61 }
    62 int d[MAXN*MAXN];
    63 bool ins[MAXN*MAXN];
    64 void SPFA() {
    65     memset(d,0x3f,sizeof(d));
    66     d[(bx-1)*m+by]=0;
    67     queue<int> q; q.push((bx-1)*m+by);
    68     ins[(bx-1)*m+by]=1;
    69     while(!q.empty()) {
    70         int u=q.front(); q.pop();
    71         ins[u]=0;
    72         for(int i=h[u];i;i=nxt[i]) {
    73             int v=to[i];
    74             if(d[v]>d[u]+dis[i]) {
    75                 d[v]=d[u]+dis[i];
    76                 if(!ins[v]) q.push(v),ins[v]=1;
    77             }
    78         }
    79     }
    80     ans=d[(ex-1)*m+ey];
    81 }
    82 int main() {
    83     scanf("%d%d",&n,&m);
    84     for(int i=1;i<=n;i++) scanf("%s",mp[i]+1);
    85     for(int i=1;i<=n;i++)
    86         for(int j=1;j<=m;j++) {
    87             if(mp[i][j]=='C') bx=i,by=j;
    88             if(mp[i][j]=='F') ex=i,ey=j;
    89         }
    90     if(noans()) {
    91         printf("no
    ");
    92         return 0;
    93     }
    94     build();
    95     SPFA();
    96     printf("%d
    ",ans);
    97     return 0;
    98 }
    t2 Code


    T3:柱状图

      法一:枚举最高点,三分最高点高度,并用树状数组计算花费,复杂度$O(nlogVlogn)$

         具体说说怎么计算花费:

          ($a$[]表示初始值,$h$[]表示最终高度)

          首先将$h_j=h_i-|i-j|$变为$$egin{cases} h_j=(h_i+i)-j &&i leq j \ h_j=(h_i-i)+j &&i>j end{cases}$$

          因为最后要求的是$ sum_{j=1}^n |h_j-a_j|$

          所以将上式代入,得:$$egin{cases} |h_j-a_j|=|(h_i+i)-(a_j+j)| &&i leq j \ |h_j-a_j|=|(h_i-i)-(a_j-j)| &&i>j end{cases}$$

          观察上式,$i$为枚举出的值,$h_i$为三分出的值,所以问题转化为如何快速求出$|C-b_j|$  $(C=h_i-i , b_j=a_j pm j)$

          $1.$可以使用平衡树:分别查询大于C的值的和、小于C的值的和、大于C的数的个数,小于C的数的个数

          $2.$可以使用树状数组:观察到使用到的值只有$a_j-j$和$a_j+j$,只有$2*n$个,

                     可以离散后插入其排名对应的位置上,达到平衡树的效果。

      

      法二:分析可得,当第$i$个数作为最高点时,如果我们将原数组减去一个先升后降的最小数列

         问题就转化为如何将新序列变都为一个数,易知一定是将其都变为$max(1,中位数)$

         如:对于数列$2,1,1,4,1$

           当以第3个数为最高点时,可以减去$0,1,2,1,0$,变为$2,0,-1,3,1$,易知将其都变为1最优(中位数),花费为6

           当以第4个数为最高点时,可以减去$0,1,2,3,2$,变为$2,0,-1,1,-1$,易知将其都变为1最优(保证原数均大于0),花费为6

         于是有了一种对于以某点为最高点时$O(n)$的计算方法

         如果枚举最高点位置,那么复杂度会变为$O(n^2)$,显然不行

         但又无法优化枚举复杂度,所以使用模拟退火算法,用$O(n)$的复杂度来check

         期望得分玄学,实际得分看rp,可AC

       法一树状数组代码:

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<vector>
     7 #include<queue>
     8 #define ll long long
     9 using namespace std;
    10 const int MAXN=200000;
    11 const ll N=2000000000;
    12 int n;
    13 ll a[MAXN],tr[4][MAXN*2],bk[MAXN*2],btot,p[MAXN*2][2];
    14 ll ans=0x3f3f3f3f3f3f3f3f;
    15 void add(int x,ll k,int id) {
    16     for(;x<=btot+1;x+=x&-x) tr[id][x]+=k;
    17 }
    18 ll ask(int x,int id) {
    19     ll ret=0;
    20     for(;x;x-=x&-x) ret+=tr[id][x];
    21     return ret;
    22 }
    23 ll check(int x,ll hi) {
    24     int pos1=upper_bound(bk+1,bk+btot+1,hi-x)-bk;
    25     int pos2=upper_bound(bk+1,bk+btot+1,hi+x)-bk;
    26     pos1=pos1?pos1-1:0;
    27     pos2=pos2?pos2-1:0;
    28     ll pres1=ask(pos1,0),sufs1=ask(btot+1,0)-ask(pos1,0);
    29     ll pres2=ask(pos2,1),sufs2=ask(btot+1,1)-ask(pos2,1);
    30     ll cnt1=ask(pos1,2),cnt2=ask(pos2,3);
    31     return ((hi-x)*cnt1-pres1)+(sufs1-(hi-x)*(x-cnt1))
    32           +((hi+x)*cnt2-pres2)+(sufs2-(hi+x)*(n-x-cnt2));
    33 }
    34 void solve(int x) {
    35     ll l=max(x,n-x+1),r=N;
    36     while(r-l>2) {
    37         ll mid1=(l+r)>>1,mid2=mid1+1;
    38         if(check(x,mid1)>check(x,mid2)) l=mid1;
    39         else r=mid2;
    40     }
    41     ans=min(ans,check(x,l));
    42     ans=min(ans,check(x,r));
    43     ans=min(ans,check(x,l+1));
    44 }
    45 int main() {
    46     scanf("%d",&n);
    47     for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    48     for(int i=1;i<=n;i++) {
    49         bk[++btot]=a[i]-i;
    50         bk[++btot]=a[i]+i;
    51     }
    52     sort(bk+1,bk+btot+1);
    53     btot=unique(bk+1,bk+btot+1)-bk-1;
    54     for(int i=1;i<=n;i++) {
    55         p[i][0]=lower_bound(bk+1,bk+btot+1,a[i]-i)-bk;
    56         p[i][1]=lower_bound(bk+1,bk+btot+1,a[i]+i)-bk;
    57     }
    58     for(int i=1;i<=n;i++) add(p[i][1],a[i]+i,1),add(p[i][1],1,3);
    59     for(int i=1;i<=n;i++) {
    60         add(p[i][1],-a[i]-i,1);
    61         add(p[i][0],a[i]-i,0);
    62         add(p[i][1],-1,3);
    63         add(p[i][0],1,2);
    64         solve(i);
    65     }
    66     printf("%lld
    ",ans);
    67     return 0;
    68 }
    t3 Code

  • 相关阅读:
    Table of CGI variable names
    Mashup 介绍
    jQuery to Style Design Elements: 20 Impressive Plugins
    利用 Domino V8 新特性开发 Mashup 应用(转载)
    css 居中问题
    【仿某公司前台】 asp安全查询系统
    奇怪了,为什么“语句未结束”
    背景图片不重复 firefox
    关于div层的间隙, 还有img与div的间隙
    js中的return
  • 原文地址:https://www.cnblogs.com/Gkeng/p/11320169.html
Copyright © 2011-2022 走看看