20190810暑假结营考试Day2

\(100+0+50\)

LG1988 火炬

正解

  1. (当时做题时,由提示可知\(n \times m\) 范围在64位整数中,)枚举\(n \times m\)
  2. 只需枚举只含0或1的乘积,类似二进制,队列生成

思路

  1. 逆向,题目求\(m\),却枚举\(n \times m\)

\(DHOJ\ 1403\)\(JZOJ\ 3053\)

正解

  1. 50% 曼哈顿距离,坐标轴分治
  2. 100% 画图,某些情况(题解)曼哈顿距离+2,坐标轴分治

思路

  1. 一开始以为树形DP,调了快1个小时发现算法错了
  2. 50%的想到曼哈顿,但是没想到分治+加法原理
  3. 完全没画图,100%的懵了

代码

#include <bits/stdc++.h>
#define ri register int
#define N 1000003
using namespace std;

typedef long long LL;
int n,m,sx,sy;
int a[1003][1003];
int heng[1003],zong[1003];
int dis[N];
LL cnt,ans,tmp1,tmp2,tmpnow;


int main(){
    freopen("travel.in","r",stdin);
    freopen("travel.out","w",stdout);
    scanf("%d%d",&n,&m);
    char ch;
    for(ri i=1;i<=n;++i){
        for(ri j=1;j<=m;++j){
            while(ch=getchar(),(ch!='.')&&(ch!='X'));
            if(ch=='.'){
                a[i][j]=1;
                ++cnt;
            }
            else {
                heng[i]=j;//每一行每一列都只会有一个X 
                zong[j]=i;
            }
        }
    }
    for(ri i=1;i<n;++i){//对x坐标上的曼哈顿距离之和
        tmp1=(heng[i]) ? m-1 : m;
        for(ri j=i+1;j<=n;++j){
            tmp2=(heng[j]) ? m-1 : m;
            ans+=2*tmp1*tmp2*abs(j-i);
        }
    }
    for(ri i=1;i<m;++i){//对y坐标上的曼哈顿距离之和 
        tmp1=(zong[i]!=0) ? n-1 : n;
        for(ri j=i+1;j<=m;++j){
            tmp2=(zong[j]!=0) ? n-1 : n;
            ans+=2*tmp1*tmp2*abs(j-i);
        }
    }
    
    for(ri i=1;i<=m;++i){//跑列 ,找到那些需要+2(思考为什么?)的点对(哪些?) 
        if(!zong[i])continue;
        tmpnow=n-zong[i];
        ans+=2*2*(n-zong[i])*(zong[i]-1);
        int j=i+1;
        while(zong[j]&&zong[j]<zong[j-1]&&j<=m){
            tmp2=zong[j]-1;
            ans+=2*2*tmpnow*tmp2; 
            ++j; 
        } 
        
        j=i-1;
        while(zong[j]&&zong[j]<zong[j+1]&&j>=1){
            tmp1=zong[j]-1;
            ans+=2*2*tmpnow*tmp1; 
            --j;
        } 
    }
    
    for(ri i=1;i<=n;++i){//跑行 
        if(!heng[i])continue;
        ans+=2*2*(m-heng[i])*(heng[i]-1);
        tmpnow=m-heng[i];
        int j=i+1;
        while(heng[j]&&heng[j]<heng[j-1]&&j<=n){
            tmp2=heng[j]-1;
            ans+=2*2*tmpnow*tmp2; 
            ++j; 
        } 
        
        j=i-1;
        while(heng[j]&&heng[j]<heng[j+1]&&j>=1){
            tmp1=heng[j]-1;
            ans+=2*2*tmpnow*tmp1; 
            --j;
        } 
    }
    printf("%.4lf\n",(double)ans/cnt/cnt);
    return 0;
}

LG2824 HEOI2016/TJOI2016排序

正解

  1. 二分这个位置可能的数所在范围
  2. check:比mid大于等于设为1,否则设为0,升序排序相当于统计区间内1的个数,区间后面赋值为1,前面赋值为0

思路

  1. 奇妙线段树
  2. 看到修改格式,就知道是数据结构题,应想到线段树
  3. 但是排序不好维护
  4. 想到01串近似维护,不精准的排序,所以不精准的check,check精髓不用求答案与正解差了多少,只需求是否可能

猜你喜欢

转载自www.cnblogs.com/kkzt/p/11333872.html
今日推荐