前綴和(持續)

寫在前面:(2020-2-12)
發現之前學習的一些算法忘了很多,準備最近在洛谷上找一些基礎的題目做一做,熟悉一下這些基礎算法,僅僅是Ac(暴力)的,

洛谷P1387最大的正方形

題目描述
在一個n*m的只包含0和1的矩陣里找出一個不包含0的最大正方形,輸出邊長。
輸入格式
輸入文件第一行為兩個整數n,m(1<=n,m<=100),接下來n行,每行m個數字,用空格隔開,0或1.
輸出格式
一個整數,最大正方形的邊長

分析:二維前綴和的裸題,對于每個點,我們依次枚舉邊長從1到min(n,m)的正方形,因為矩陣的元素不是0就是1,所以我們利用二維前綴和計算出正方形中1的個數是否等于該正方形的面積,ans維護答案即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 1010;

int n,m;
int a[N][N];
int s[N][N];

bool check(int x1,int y1,int x2,int y2)
{
    int res = (x2-x1+1) * (y2-y1+1);
    int t = s[x2][y2] - s[x1-1][y2] - s[x2][y1-1] + s[x1-1][y1-1];
    if(t == res) return true;
    return false;
}
int main()
{
    cin>>n>>m;
    for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m; j++)
            scanf("%d",&a[i][j]);
            
    
    for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m; j++)
            s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + a[i][j];
    
    int len = min(n,m);  //正方形的邊長不可能超過n和m中小的那一個
    int ans = 0;
    for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m; j++)
            for(int k = 1; k<=len; k++)
            {
                if(i+k-1 >n || j+k-1 >m) continue;
                if(check(i,j,i+k-1,j+k-1))
                {
                    ans = max(ans,k);
                    //cout<<ans<<endl;
                }
            }
    cout<<ans<<endl;
    return 0;
}

洛谷P2280激光炸彈

題目

很容易看出,此題和上題一樣,是個二維前綴和的題目,但是由于處于正方形的邊上的目標不會被摧毀,我們可以做一個轉化,對二維前綴和來說,我們認為每個元素代表一個格子,所以,這題我們可以認為這些目標處于格子的中心,這樣格子的左上角坐標是(Xi-0.5,Yi-0.5),右下角坐標是(Xi+0.5,Yi+0.5),而右下角處于格子交線上,所以我們依次枚舉邊長為R的正方形,利用二維前綴和維護答案即可。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int N = 5050;

int a[N][N];
int u,r;

int main()
{
    cin>>u>>r;
    
    r = min(r,5001);
    for(int i = 0; i<u; i++)
    {
        int x,y,w;
        cin>>x>>y>>w;
        a[x+1][y+1] = w;
    }
    
    //預處理前綴和
    int n = 5001,m = 5001;
    for(int i = 1; i<=n; i++)
        for(int j = 1; j<=m; j++)
            a[i][j] += a[i-1][j] + a[i][j-1] - a[i-1][j-1];
        
    int ans = 0;
    
    for(int i = r; i<=n; i++)
        for(int j = r; j<=m; j++)
        {
            ans = max(ans,a[i][j] - a[i-r][j] - a[i][j-r] + a[i-r][j-r]);
            //cout<<ans<<" "<<i<<" "<<j<<endl;
        }
            
    cout<<ans<<endl;
    return 0;
}

洛谷P1114非常男女計劃

題目描述
近來,初一年的XXX小朋友致力于研究班上同學的配對問題(別想太多,僅是舞伴),通過各種推理和實驗,他掌握了大量的實戰經驗。例如,據他觀察,身高相近的人似乎比較合得來。
萬圣節來臨之際,XXX準備在學校策劃一次大型的“非常男女”配對活動。對于這次活動的參與者,XXX有自己獨特的選擇方式。他希望能選擇男女人數相等且身高都很接近的一些人。這種選擇方式實現起來很簡單。他讓學校的所有人按照身高排成一排,然后從中選出連續的若干個人,使得這些人中男女人數相等。為了使活動更熱鬧,XXX當然希望他能選出的人越多越好。請編寫程序告訴他,他最多可以選出多少人來。
輸入格式
第一行有一個正整數n,代表學校的人數。n≤100000
第二行有n個用空格隔開的數,這些數只能是0或1,其中,0代表一個女生,1代表一個男生
輸出格式
輸出一個非負整數。這個數表示在輸入數據中最長的一段男女人數相等的子序列長度。
如果不存在男女人數相等的子序列,請輸出0。

先想一想暴力的方法,枚舉左右端點,前綴和計算區間的和(把女生的值設為-1),用ans來維護答案,這樣暴力的復雜度是O(N^2),顯然是通過不了的,其實在第二層循環那里可以優化一下,第二層循環從后向前枚舉,如果當前枚舉區間的長度小于ans,直接break,效率將大大提升。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

const int N = 101000;

int n;
int a[N];
int s[N];

int main()
{
    scanf("%d",&n);
    
    for(int i = 1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        if(!a[i]) a[i] = -1;
        s[i] = s[i-1] + a[i];
    }
    
    int ans = 0;
    for(int i = 1; i<=n; i++)
    {
        for(int j = n; j>=i+1; j--)
        {
            if(j-i+1 <ans) break;  //如果當前枚舉的長度小于ans,不需要再往后遍歷了
            if(s[j] - s[i-1] == 0)
                ans = max(ans,j-i+1);
        }
    }
    cout<<ans<<endl;
    return 0;
}

(更新-2020-3-25)

Codeforces#Round624C題-Perform the combo

我們可以使用前綴和解決這道題目:先記錄每個字母出現的次數,然后求一遍前綴和,累加到答案中即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 2e5+100;

int t,n,m;
int p[N], a[N][26],ans[26];
char s[N];
int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        scanf("%s",s+1);
        for(int i = 1; i<=m; i++) scanf("%d",&p[i]);

        //這里如果使用memset清空數組會超時
        for(int i = 1; i<=n; i++)
            for(int j = 0; j<26; j++)
                a[i][j] = 0;
        for(int i = 0; i<26; i++) ans[i] = 0;

        //記錄每個字符出現的次數
        for(int i = 1; i<=n; i++) a[i][s[i]-'a'] ++;

        //求一遍前綴和,ans[i][j]即表示前i個字符中,字母j一共出現了多少次
        for(int i = 1; i<=n; i++)
            for(int j = 0; j<26; j++)
                a[i][j] += a[i-1][j];

        for(int i = 1; i<=m; i++)
            for(int j = 0; j<26; j++)
                ans[j] += a[p[i]][j];

        for(int i = 0; i<26; i++) ans[i] += a[n][i];
        for(int i = 0; i<26; i++) printf("%d ",ans[i]);
        puts("");
    }
    return 0;
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,825評論 6 546
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,814評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,980評論 0 384
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 64,064評論 1 319
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,779評論 6 414
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,109評論 1 330
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,099評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,287評論 0 291
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,799評論 1 338
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,515評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,750評論 1 375
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,221評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,933評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,327評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,667評論 1 296
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,492評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,703評論 2 380

推薦閱讀更多精彩內容

  • Educational Codeforces Round 81 題解 A - Display The Number...
    frans4x閱讀 262評論 0 0
  • 1. file n. 文件;v. 保存文件2. command n. 命令指令3. use v. 使用用途4. p...
    喵嗚Yuri閱讀 765評論 0 4
  • 生活大爆炸版石頭剪刀布 題目描述 石頭剪刀布是常見的猜拳游戲:石頭勝剪刀,剪刀勝布,布勝石頭。如果兩個人出拳一樣,...
    bbqub閱讀 471評論 0 0
  • 這是16年5月份編輯的一份比較雜亂適合自己觀看的學習記錄文檔,今天18年5月份再次想寫文章,發現簡書還為我保存起的...
    Jenaral閱讀 2,819評論 2 9
  • 宅在家里,看《急診科醫生》,一天看了十幾集,看得心驚肉跳,又對醫護人員敬佩不已。 他們每天面對的是血肉模糊的火災燒...
    總有新期待閱讀 176評論 0 0