今天出題人出了三道看似很難,實則暴力就能過的題...我...ios
T1 題意簡述:jzoj3452數組
解題思路:這題...看似是一道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
解題思路:這道題個人第一反應是先找圖上的簡單環,而後枚舉每條被刪除的邊看是否能每一個環分到一
條邊或分不到邊,多餘的未分配邊數即等於增長的連通塊數。
雖然想法是徹底正確的,可是找簡單環可一點也不容易...到考試結束我也沒寫出來。
看過題解,有種想吐血的衝動。題解給出的方法以下:
記錄兩個並查集數組分別表示加入前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
解題思路:各位大佬猜這道題的正解是什麼?
揭曉答案:暴力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; }