首页 > 其他分享 >E - Dividing Chocolate --- detecting next end point by double expand & half fold way

E - Dividing Chocolate --- detecting next end point by double expand & half fold way

时间:2023-02-16 21:55:48浏览次数:34  
标签:presee end cout Dividing point int curpos step hlines

E - Dividing Chocolate

https://atcoder.jp/contests/abc159/tasks/abc159_e

 

思路

对于不大于k位置的查找,

前一篇给出了基于前缀和的 从左向右逐步查找方法

https://www.cnblogs.com/lightsong/p/17124860.html

 

对于上规模的w情况, 即w很大的情况,

同时白块比较稀疏, 每次向右移动一格的方法, 过于低效

 

本文给出启发式搜索方法:

以向右探测的步骤作为观察标准 presee

初始设置 presee 为 1

如果不大于x,

presee扩大二倍,

如果还是不大于x

presee再扩大二倍

 

类似TCP超时重试的机制。

参考:

https://atcoder.jp/contests/abc159/submissions/38882293

 对于此代码的解决方案, 文末给出详细的注释版代码。

 

Code

https://atcoder.jp/contests/abc159/submissions/38928832

 
int h, w, k;
vector<vector<int>> s(16, vector<int>(1006, 0));
//int s[16][1006];
 
// prefix sum
vector<vector<int>> ps(16, vector<int>(1006, 0));
//int ps[16][1006];
 
int main()
{
    cin >> h >> w >> k;
 
    REP(i, h){
        int hi = i+1;
 
        REP(j, w){
            int wj = j+1;
 
            char one;
            cin >> one;
 
            s[hi][wj] = (one=='1'?1:0);
 
            ps[hi][wj] = s[hi][wj] + ps[hi-1][wj] + ps[hi][wj-1] - ps[hi-1][wj-1];
        }
    }
 
    if (ps[h][w] <= k){
        cout << 0 << endl;
        return 0;
    }
 
    int mincuts = (h-1) * (w-1);
 
    // horizontally split
    for(int i=0; i<(1<<(h-1)); i++){
//        cout << "----------- combination i = " << i << " ----------" << endl;
 
        // figure out cuts of horizons
        vector<int> hcuts;
        for(int j=1;j<h; j++){
//            cout << "j = " << j << endl;
            if((i>>(j-1)) & 1){
                hcuts.push_back(j);
            }
        }
 
//
//        cout << "------ hcuts: combination individual cases --------" << endl;
//        REP(j, hcuts.size()){
//            cout << hcuts[j] << " ";
//        }
//        cout << endl;
 
        /* hlines: 0 1 3
        ------ 0
        1 2 3
        ------ 1
        4 5 6
        7 8 9
        ----- 3
        */
 
        vector<int> hlines;
        hlines.push_back(0);
        REP(j, hcuts.size()){
            hlines.push_back(hcuts[j]);
        }
        hlines.push_back(h);
//
//        cout << "--------- hlines --------" << endl;
//        REP(j, hlines.size()){
//            cout << hlines[j] << " ";
//        }
//        cout << endl;
 
        // vertically split
        /*
        vlines: 0 1 3
        |1|2 3|
        |4|5 6|
        |7|8 9|
        0 1   3
        */
 
        vector<int> vlines;
        vlines.push_back(0);
        bool hcuts_abort = false;
        
        while(true){
            int vline_start = vlines[vlines.size()-1];
            
            int curpos = vline_start;
            int presee = 1;
 
            while(presee){
                int vline_presee = curpos + presee;
 
//                cout << "try presee, it value=" << presee << endl;
                int hlines_len = hlines.size();
                
                /*
                --------- 0
                |1|2 3|
                --------- 1
                |4|5 6|
                |7|8 9|
                --------- 3
                0 1   3
                */
                bool greatk = false;
                
                for(int i=1; i<hlines_len; i++){
                    int hline_start = hlines[i-1];
                    int hline_end = hlines[i];
 
//                    cout << "hline_start=" << hline_start << endl;
//                    cout << "hline_end=" << hline_end << endl;
 
                    int rectsum = ps[hline_end][vline_presee]
                        - ps[hline_end][vline_start]
                        - ps[hline_start][vline_presee]
                        + ps[hline_start][vline_start];
 
//                    cout << "rectsum = " << rectsum << endl;
 
                    if (rectsum>k){
                        greatk = true;
                        break;
                    }
                }
 
                if(greatk){
                    presee>>=1;
                } else {
                    // for presee step, no sections sum great than k
                    // change current position to presee position
                    curpos = vline_presee;
                    
                    // increase presee step by 2 times
                    presee<<=1;
                    if (curpos+presee >= w){
                        presee = w - curpos;
                    }
                }
            }
 
            if (curpos == vline_start){
                hcuts_abort = true;
                break;
            } else {
                if (curpos == w){
                    break;
                }
                
                vlines.push_back(curpos);
            }
        }
 
        if(hcuts_abort){
//            cout << "----------- combination i = " << i << " aborted ----------" << endl;
            continue;
        }
//
//        cout << "----------- combination i = " << i << " met, its solution ----------" << endl;
//
//        cout << "--------- hlines --------" << endl;
//        REP(j, hlines.size()){
//            cout << hlines[j] << " ";
//        }
//        cout << endl;
//
//        cout << "--------- vlines --------" << endl;
//        REP(j, vlines.size()){
//            cout << vlines[j] << " ";
//        }
//        cout << endl;
 
        int cuts_num = hlines.size() - 2 + vlines.size() - 1;
//        cout << "----- current combination cuts ------";
//        cout << cuts_num << endl;
 
        mincuts = min(mincuts, cuts_num);
    }
 
    cout << mincuts << endl;
 
    return 0;
}
 

 

参考方案详解

https://atcoder.jp/contests/abc159/submissions/38882293

// Code 2
// O(2^H*(log W)*H)
#include<bits/stdc++.h>
using namespace std;
const bool ZJS_AK_IOI=1;//fast read&write or not
int n,m,x;

char c[50][1020];

int s[50][1020];
bool hlines_used[50];

int ans=INT_MAX;

void solve()
{
    cin>>n>>m>>x;
    
    /*
    for every row, calculate prefix sum from left to right
    for example
    1 2 3
    --->
    1 3 6
    */
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>c[i][j];
            s[i][j]=s[i][j-1]+(c[i][j]=='1');
            // cout<<s[i][j]<<" \n"[j==m];
        }
    }
    
    /*
    regarding to every case of row combination,
    look into splitting it vertically
    
    explaination for 1 << n-1
    n-1 : there are n-1 lines for cutting
    for example:
    1 2 3
    -------- line one for cutting
    4 5 6
    -------- line two for cutting
    7 8 9
    
    1<<n-1 : there are 2^(n-1) cases of row combination
    for example:
    4 cases for cutting regarding to 3 rows
    
    list:
    empty
    line one
    line two
    line one & line two
    
    bits presentation:
    1 1 == n-1 == 2
    0 0 --- empty
    0 1 --- line one
    1 0 --- line two
    1 1 --- line one & line two
    
    k is the bits presetation for every case
    */
    for(int k=0;k<(1<<n-1);k++)
    {
        /*
        how many lines are selected for cutting
        */
        int cuts_num=0;
        
        /*
        hlines_used arrary to record which lines are in the this combination case
        h means horizontal
        hlines_used[1] -- line one
        hlines_used[2] -- line two
        .....
        */
        memset(hlines_used,0,sizeof(hlines_used));
        
        /*
        kk is the power(2^kk) of line in the bits presentation
        such as
        1 1
        line one is corresponding to later one, with the power 0 -- 01 = 0*2^1 + 1*2^0
        line two is corresponding to former one, with the power 1 -- 10 = 1*2^1 + 0*2^0
        */
        for(int kk=0;kk<n;kk++)
        {
            /*
            k is the bits presentation of row combination case
            decrease the power of k by kk
            it means making the bit of kk power to rightmost position
            for example:
            1010 >> 1 ==> 101
            then we can use 101&1 == 1 to test if the power kk bit position are occupied
            i.e. line kk+1 is selected for cutting
            so set hlines_used[kk+1] = 1
            */
            if((k>>kk)&1)
            {
                hlines_used[kk+1]=1;
                cuts_num++;
            }
            // cout<<f[kk+1]<<" \n"[kk==n-1];
        }
        
        /*
        Is there one possible way to cut vertically
        i.e. cn find vertical cuts
        such as
        1 2 | 3
        4 5 | 6
        7 8 | 9
        */
        bool vcuts_ok=1;
        
        int lst=0;
        int p=1,step=0;
        
        while(step<m)
        {
            while(p)
            {
                /*
                white_num:
                how many white blocks are counted in one reactangle
                for example, there are four rectangles by this cuts:
                1 2 | 3
                -------
                4 5 | 6
                7 8 | 9
                */
                int white_num=0;
                
                /*
                Is the white blocks not great than x
                */
                bool not_great_x = true;
                
                /*
                for all horizontal cuts sections,
                decide if all sections white blocks number is not great than x
                from 1st postion to step+p
                */
                for(int i=1;i<=n;i++)
                {
                    white_num += s[i][step+p] - s[i][lst];
                    
                    if(white_num>x)
                    {
                        not_great_x = false;
                        break;
                    }
                    
                    if(hlines_used[i]){
                        white_num=0;
                    }
                }
                
                // cout<<step+p<<" "<<lst<<" "<<cnt<<endl;
                /*
                not_great_x == true
                means
                for (1st, step+p] interval of width direction
                the white block numbers of all horizontal cuts sections are not great than x
                then we can move step much further
                for example:
                1st = 0
                step = 0
                p = 1

                1 2 3
                -------
                4 5  6
                7 8  9

                there are two horizontal cuts sections
                section one:
                1 2 3
                
                section two:
                4 5  6
                7 8  9

                for section one, it will count one element 1
                |1| 2 3

                for section two, it will count two element 4 7
                |4| 5  6
                |7| 8  9
                */
                if(not_great_x)
                {
                    /*
                    change current position to predicted postion
                    step -> step + p
                    */
                    step += p;
                    
                    if(step==m){
                        break;
                    }

                    /*
                    beacuse it is ok for (1st, step+p] interval
                    we want to enlarge this interval to increase efficiency
                    like gredient descent algorithm
                    policy is to enlarge by multipling by two
                    */
                    p = min(p<<1, m-step);
                }
                else
                {
                    p>>=1;
                    
                    if(p==0)
                    {
                        if(step==lst){
                            vcuts_ok=false;
                        }

                        break;
                    }
                }
            }
            
            if(!vcuts_ok){
                break;
            }
            
            lst=step;
            p=1;
            
            cuts_num++;
        }
        
        if(vcuts_ok){
            ans=min(ans,cuts_num);
        }
    }
    
    cout<<ans-1<<endl;
}

int main()
{
    if(ZJS_AK_IOI){ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);}
    // int t;cin>>t;while(t--)
    solve();
    return 0;
}

 

标签:presee,end,cout,Dividing,point,int,curpos,step,hlines
From: https://www.cnblogs.com/lightsong/p/17128444.html

相关文章

  • 在Teams团队中快速添加SharePoint Online站点
    前言我们在使用Office365的过程中,经常会在Teams里创建团队,用来管理项目组和收藏文档,但是,很多信息以文件形式存放并不是一个好的方式。所以,我们就可以把一些......
  • Office 365 中邮件自动存档到SharePoint Online文档库
    前言大家有没有这样的烦恼,就是公司邮件居多,领导问你要一个月前的文件,你根本无从查找,好吧,学会归档很重要。正文1.我先创建一个文档库,用来保存Outlook中......
  • E - Dividing Chocolate
    E-DividingChocolatehttps://atcoder.jp/contests/abc159/tasks/abc159_e 思路https://www.cnblogs.com/ycx-akioi/p/AtCoder-abc159.htmlCodehttps://atcoder.......
  • 【解决方案】docker: Error response from daemon: endpoint with name nacos already
    问题描述修改nacos配置时,保存报错于是重启nacos,nacos使用Docker部署。重启nacos容器时,遇到如下问题:[root@localhost~]#dockerstartb7236a0545a3Errorrespons......
  • 富文本编辑器实现导入PowerPoint
    ​ 百度ueditor新增的将word内容导入到富文本编辑框的功能怎么没有啊,...ueditor实现word文档的导入和下载功能的方法:1、UEditor没有提供word的导入功能,只能说是粘贴复......
  • 富文本编辑器实现一键导入PowerPoint
    ​ 自动导入Word图片,或者粘贴Word内容时自动上传所有的图片,并且最终保留Word样式,这应该是Web编辑器里面最基本的一个需求功能了。一般情况下我们将Word内容粘贴到Web编辑......
  • echarts legend设置多组形状
    当echarts中既有条形图又有折线图时,legend也有两种:想实现以下效果改如何配置呢  其实前面两个并没有对legend进行设置,是给series添加了type:'line'的事件办结率数......
  • endl超时
    2023牛客寒假练习5-E#include<iostream>#include<algorithm>#include<numeric>#include<vector>usingnamespacestd;typedefpair<int,int>pii;intmain(){......
  • SharePoint Online 根据已存在列表创建列表
    前言在SharePointOnline的使用中,根据已经存在的列表进行列表创建,是经常的操作。尤其,当我们在一个租户上创建不同SharePoint站点作为开发、测试、生产环境的时候......
  • SharePoint Online 根据Excel文件创建列表
    前言在SharePointOnline的使用中,根据Excel文件进行列表创建,是经常的操作。尤其,当我们在一个Excel上设计了站点结构的时候。正文1.在网站内容页面中,点......