2018.8.18提升B組模擬試題

今天出題人出了三道看似很難,實則暴力就能過的題...我...ios

 

T1 題意簡述:jzoj3452數組

 

Description

雞腿是CZYZ的著名DS,可是不想學數學的DS不是好GFS,因此雞腿想經過提升數學水平來加強他的GFS氣質!雖然你對雞腿很無語,可是故事的設定是你幫助雞腿加強了GFS氣質,因此如今你必須教雞腿學數學! 

雞腿想到了一個很高(sha)明(bi)的問題,在 N 條水平線與 M 條豎直線構成的網格中,放 K 枚石子,每一個石子都只能放在網格的交叉點上。問在最優的擺放方式下,最多能找到多少四邊平行於座標軸的長方形,它的四個角上都剛好放着一枚石子。 

Input

一行輸入三個正整數N,M,K。 

Output

一行輸出一個正整數,表示最多的知足條件的長方形數量。 

Data Constraint

對於50%的數據0 < N, M ≤ 30; 

對於100%的數據0 < N, M ≤ 30000;K ≤ N*M。

 

   解題思路:這題...看似是一道dp...實則是一道結論題...ui

             能夠發現矩形數量最多當且僅當石子知足如下兩種擺放順序之一:spa

             XXX...XXX   或   XXX...XXXXX
.net

             XXX...XXX        XXX...XXX
code

             ...              ...
blog

             XXX...XXX        XXX...XXX
ip

             XXget

             所以只需枚舉除最後一行(列)外每行(列)有幾個石子,而後計算便可。數學

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
ll n,m,k,ans;
int main()
{
    freopen("rectangle.in","r",stdin);
    freopen("rectangle.out","w",stdout);
    scanf("%lld%lld%lld",&n,&m,&k);
    for(ll i=2;i<=m;i++)
    {
        ll x=k/i,y=k%i;
        if(!x) break;
        if(x>n||(x==n&&y)) continue;
        ll tmp=x*(x-1)/2*i*(i-1)/2+y*(y-1)/2*x;
        ans=max(ans,tmp);
    }
    for(ll i=2;i<=n;i++)
    {
        ll x=k/i,y=k%i;
        if(!x) break;
        if(x>m||(x==m&&y)) continue;
        ll tmp=x*(x-1)/2*i*(i-1)/2+y*(y-1)/2*x;
        ans=max(ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}

 


 

T2 題意簡述:jzoj3453

 

Description

你應該知道無向圖的連通塊的數量,你應該知道如何求連通塊的數量。當你興奮與你的成就時,破壞王Alice拆掉了圖中的邊。當她發現,每刪去一條邊,你都會記下邊的編號,同時告訴她當前連通塊的個數。 

 然而,對邊編號簡直就是個悲劇,由於Alice爲了刁難你,拆掉編號從l到r的邊,固然你須要作的事情就是求連通塊的個數。若是你答對了,Alice會把拆掉的邊裝好,迚行下一次破壞。若是你沒法完成這個任務,Alice會完全毀了你的圖。 

進行完足夠屢次以後,Alice以爲無聊,就玩去了,而你卻須要繼續作第三題。

Input

第一行兩個整數n,m,表示點數和邊數。 

以後m行每行兩個整數x,y,表示x與y之間有無向邊。(按讀入順序給邊編號,編號從1開始) 

 一行一個整數k,表示Alice的破壞次數。 

 以後k行,每行兩個整數l,r。 

Output

 k行,每行一個整數。 

Data Constraint

對於30%的數據,n<=100,k<=10 

對於60%的數據,k<=1000 

對於100%的數據,n<=500,m<=10000,k<=20000,1<=l<=r<=m

 

   解題思路:這道題個人第一反應是先找圖上的簡單環,而後枚舉每條被刪除的邊看是否能每一個環分到一

             條邊或分不到邊,多餘的未分配邊數即等於增長的連通塊數。

             雖然想法是徹底正確的,可是找簡單環可一點也不容易...到考試結束我也沒寫出來。

             看過題解,有種想吐血的衝動。題解給出的方法以下:

             記錄兩個並查集數組分別表示加入前i條邊與後i條邊後的連通塊狀況。詢問時合併便可。

             ...我仍是太蠢了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,k,fa[501],prefa[10002][501],suffa[10002][501];
struct uio{
    int a,b;
}edge[10001];
int getprefa(int x,int id)
{
    if(x==prefa[id][x]) return x;
    return prefa[id][x]=getprefa(prefa[id][x],id);
}
int getsuffa(int x,int id)
{
    if(x==suffa[id][x]) return x;
    return suffa[id][x]=getsuffa(suffa[id][x],id);
}
int getfa(int x)
{
    if(x==fa[x]) return x;
    return fa[x]=getfa(fa[x]);
}
int main()
{
    freopen("connect.in","r",stdin);
    freopen("connect.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        prefa[0][i]=suffa[m+1][i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&edge[i].a,&edge[i].b);
        memcpy(prefa[i],prefa[i-1],sizeof(prefa[i-1]));
        int xx=getprefa(edge[i].a,i);
        int yy=getprefa(edge[i].b,i);
        if(xx!=yy) prefa[i][yy]=xx;
    }
    for(int i=m;i;i--)
    {
        memcpy(suffa[i],suffa[i+1],sizeof(suffa[i+1]));
        int xx=getsuffa(edge[i].a,i);
        int yy=getsuffa(edge[i].b,i);
        if(xx!=yy) suffa[i][yy]=xx;
    }
    scanf("%d",&k);
    for(int i=1;i<=k;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        memcpy(fa,prefa[u-1],sizeof(prefa[u-1]));
        for(int j=1;j<=n;j++)
        {
            int xx=getfa(j);
            int yy=getsuffa(j,v+1);
            int zz=getfa(yy);
            if(xx!=zz) fa[xx]=zz;
        }
        int tmp=0;
        for(int j=1;j<=n;j++)
            if(getfa(fa[j])==j) tmp++;
        printf("%d\n",tmp);
    }
    return 0;
}

 


 

T3 題意簡述:jzoj3450

 

Description

做爲地質學家的JIH,爲了繪製地圖進行了野外考察。考察結束,他獲得了一張n*m的地面高度地圖。爲了科學研究,JIH定義了一種山峯叫作d-山峯。一個高度爲h地點被稱做d-山峯,只有知足從這裏出發,在不通過小於等於h-d的地點的前提下沒法達到比它更高的地方。JIH正糾結於怎麼分禮物,標出d-山峯的任務就交給你了。

Input

第一行n,m,d

第二行開始,有一個n*m的矩陣表示地圖,用空格隔開。

Output

輸出d-山峯的個數。

Data Constraint

30% n,m<=10

100% n,m<=500

 

   解題思路:各位大佬猜這道題的正解是什麼?

             揭曉答案:暴力dfs+一個愚蠢的剪枝。

             ...這種題目出如今提升B組真的好嗎?

             至於那個愚蠢的剪枝,爲了避免浪費各位大佬的時間,博主稍微解釋一下:

             沒必要每搜一個點就把vis數組清空一次,只需把標記打成這個點的標號便可。

             ...足夠愚蠢吧?

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
int n,m,k,ans,flg,a[501][501],vis[501][501];
void dfs(int x,int y,int num,int id)
{
    vis[x][y]=id;
    if(a[x][y]>num) {flg=1;return;}
    if(x!=1&&a[x-1][y]>num-k&&vis[x-1][y]!=id) dfs(x-1,y,num,id);
    if(flg) return;
    if(x!=n&&a[x+1][y]>num-k&&vis[x+1][y]!=id) dfs(x+1,y,num,id);
    if(flg) return;
    if(y!=1&&a[x][y-1]>num-k&&vis[x][y-1]!=id) dfs(x,y-1,num,id);
    if(flg) return;
    if(y!=m&&a[x][y+1]>num-k&&vis[x][y+1]!=id) dfs(x,y+1,num,id);
    if(flg) return;
}
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    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++)
        {
            flg=0;
            dfs(i,j,a[i][j],(i-1)*m+j);
            if(!flg) ans++;
        }
    printf("%d\n",ans);
    return 0;
}
相關文章
相關標籤/搜索