一共四道編程. 前兩道比較簡單就不說了, 主要講講3,4道.
第三題: 開心消消樂
就是給你個M*N的二維矩陣, 每個塊有一個顏色, 如果它的四周有相同的顏色那麼就是連在一起的, 每次點擊一個色塊(要能點擊消除儘量多的, 如果有數量相同的點擊編號小的)進行消除, 然後消除後上面的掉下來, 如果某一列消失了, 右邊的補過來. 問最後這個矩陣還剩多少個方塊…
題解: 按照題意模擬即可, 每次dfs找出能消除最多的, 然後標記這些塊, 再寫個函數處理一下消除後的填充小果果, 一直處理下去就行. 考查代碼力.
AC Code
const int M = 55;
const int N = 25;
bool vis[M][N];
char s[M][N], ts[M][N];
int dx[] = {1, -1, 0, 0};
int dy[] = {0, 0, 1, -1};
int n, m;
void dfs(int x, int y, int &cnt, int flag) { // 找消除塊, 還能標記這些塊
vis[x][y] = 1; ++ cnt;
if (flag) ts[x][y] = '#';
for (int i = 0 ; i < 4 ; ++ i) {
int xx = x + dx[i];
int yy = y + dy[i];
if (xx < 1 || xx > m || yy < 1 || yy > n) continue;
if (s[xx][yy] != s[x][y] || vis[xx][yy] || s[xx][yy] == '#') continue;
dfs(xx, yy, cnt, flag);
}
}
void work() { // 處理消除這些塊後矩陣的樣子
for (int i = 1 ; i <= n ; ++ i) {
int low = m, high = m-1;
while(low >= 1 && high >= 1) {
if (ts[low][i] != '#') -- low;
else {
high = low - 1;
while(high >= 1 && ts[high][i] == '#') -- high;
if (high >= 1) {
swap(ts[low][i], ts[high][i]);
-- low;
}
}
}
}
int f = 0;
for (int i = 1 ; i < n ; ++ i) {
if (ts[m][i] == '#') {
f = 1;
for (int j = 1 ; j <= m ; ++ j) {
ts[j][i] = ts[j][i+1];
}
ts[m][i+1] = '#';
}
}
if (f) for (int j = 1 ; j <= m ; ++ j) ts[j][n] = '#';
memcpy(s, ts, sizeof(s));
}
void solve() {
scanf("%d%d", &m, &n);
for (int i = 1 ; i <= m ; ++ i) {
scanf("%s", s[i]+1);
}
int tot = 0;
int ti = 0;
while(1) {
++ ti;
memset(vis, 0, sizeof(vis));
int mx = 0, sx = -1, sy = -1;
for (int i = 1 ; i <= m ; ++ i) {
for (int j = 1 ; j <= n ; ++ j) {
if (s[i][j] == '#' || vis[i][j]) continue;
int cnt = 0;
dfs(i, j, cnt, 0);
if (cnt > mx) {
mx = cnt; sx = i, sy = j;
}
else if (cnt == mx && s[i][j] - '0' < s[sx][sy] - '0') {
sx = i, sy = j;
}
}
}
tot += mx <= 1 ? 0 : mx;
if (mx <= 1) break;
int cnt = 0;
memset(vis, 0, sizeof(vis));
memcpy(ts, s, sizeof(s));
dfs(sx, sy, cnt, 1);
work();
}
printf("%d\n", m*n - tot);
}
第四題: 數矩形
1
4
1 1
2 2
3 3
4 4
輸出5
題解: 這道題還是挺有意思的… 通過畫圖可以知道, 實際上就看能多分割出多少個矩形, 如果x2 < x1, 但是y2 > y1, 那就多分出了一個矩形了, 實際上有點像偏序, 也就是在確定好x的大小關係後, 尋找 當前比這個y小的有多少個, 有多少就加多少(注意處理x或者y相同的情況). 所以我們需要一個數據結構可以幫我們判斷出某個數是否在裏面, 比某個數小的數量是多少. 很明顯set(無法算數量)做不到, 我們要做的就是模擬這個功能的set, 我用的離散化 + 樹狀數組.
AC Code
const int maxn = 1e5+5;
struct BinaryIndexTree { // 離散化 + 樹狀數組的模板
int a[maxn], c[maxn], idx, siz;
bool d[maxn];
BinaryIndexTree() {clear();}
void push_back(int x){a[++idx]=x;}
int size() {return siz;}
void build() {
sort(a+1, a+1+idx);
idx = unique(a+1, a+1+idx) - a - 1;
}
bool exist(int x){ return d[get(x)]; }
int get(int x) {
return lower_bound(a+1, a+1+idx,x) - a;
}
void insert(int x) {
int y = get(x);
++siz, d[y]=true;
for(int i = y ; i <= idx ; i += i&-i)
++ c[i];
}
int sum(int p) {
int res = 0;
for(int i = p ; i ; i -= i&-i)
res += c[i];
return res;
}
//<=x的數的個數
int lower(int x){ return sum(get(x)); }
void clear() {
for(int i = 0 ; i <= idx ; ++i)
c[i] = d[i] = 0;
idx = siz =0;
}
}bit;
struct node {
int x,y;
bool operator<(const node &_) const {
if (x != _.x) return x > _.x;
return y > _.y;
}
}a[maxn];
void solve() {
int n;
scanf("%d",&n);
for (int i = 1 ; i <= n ; ++ i) {
scanf("%d%d",&a[i].x,&a[i].y);
bit.push_back(a[i].y);
}
sort(a+1,a+1+n);
bit.build();
ll ans=0;
for(int i = 1 ; i <= n ; ++i) {
if(a[i].x != a[i-1].x) // x相同, 不用計算小的值
ans+=bit.lower(a[i].y);
if(!bit.exist(a[i].y)) {
++ans; // 本身, 然後再把不在set的y插進去. 不重複加
bit.insert(a[i].y);
}
}
printf("%lld\n",ans);
bit.clear();
}