AcWing 每日一題 - Summer


本篇解題記錄題源來自 AcWing 的 Summer 每日一題

補題鏈接:Here

2021/07/01 done

Week 1

星期一 AcWing 3485. 最大異或和 (Hard

思路
先求出前i個數的異或和sum[i],再在大小為m的滑動窗口內進行trie.

QQ圖片20210510213023.jpg

  • \(\mathcal{O}(nlog\ n)\)
int n, m;
const int N = 31e5 + 10;  //最多有n*31
int p[N][35], ct[N], idx; //ct[n]的作用是標記滑動窗口內0,1的數量

int sum[100010]; //sum[i]存前i個數的異或和
void insertt(int u, int c) {
    int t = 0;
    for (int i = 30; i >= 0; i--) {
        int x = u >> i & 1;
        if (!p[t][x]) {
            p[t][x] = ++idx;
        }
        t = p[t][x];
        ct[t] += c; //標記這里(有或刪除)一個數可以達到該位置
    }
}
int query(int u) {
    int t   = 0;
    int res = u;
    for (int i = 30; i >= 0; i--) {
        int x = u >> i & 1;
        if (ct[p[t][!x]] > 0) { //當x對面的那個數!x存在時(0,1)
            x = (x + 1) % 2;    //x就變成另外一個數 !x
        }
        res ^= x << i;
        t = p[t][x];
    }
    return res;
}
void solve() {
    cin >> n >> m;
    int t;
    for (int i = 1; i <= n; i++) {
        cin >> t;
        sum[i] = sum[i - 1] ^ t; //sum[i]表示前i個數的^
    }
    insertt(0, 1); //插入0,是為了方便前m個數進行異或得出的答案可以是它本身的值
    int res = 0;   //求最大值
    for (int i = 1; i <= n; i++) {
        if (i > m) insertt(sum[i - m - 1], -1); //將滑動窗口外的數除去,這時就要修改ct,故-1
        res = max(res, query(sum[i]));          //在滑動窗口內求最大值
        insertt(sum[i], 1);                     //求完后記得插入該值,方便后面的值進行異或
    }
    cout << res;
}

星期二 AcWing 3493. 最大的和 (Easy

對於 \(30\%\) 數據,可以開兩重 for 循環暴力找

但在 \(100\%\) 數據里肯定會 T

所以要用前綴和進行優化 (當然也可以用隊列優化,這里就不展開了,貼一個講解鏈接

  • \(\mathcal{O}(n)\)
using ll    = long long;
const int N = 1e5 + 10;
ll a[N], s[N];
ll st[N];
void solve() {
    int n, k;
    cin >> n >> k;
    for (int i = 1; i <= n; ++i) cin >> a[i];
    ll sum = 0;
    for (int i = 1; i <= n; ++i) {
        cin >> st[i];
        if (st[i]) s[i] += s[i - 1], sum += a[i]; // 如果是 st[i] = 1 的情況說明直接就可選,sum 累加即可
        else
            s[i] = s[i - 1] + a[i]; // 需要轉換狀態的話則要利用前綴和累加了
    }
    ll res = 0;
    for (int i = k; i <= n; ++i) res = max(res, s[i] - s[i - k]);
    cout << res + sum;
}

星期三 AcWing 3499. 序列最大收益 (Mid

參考最長上升子序列

  • f[i][j] 表示從0~i-1 中刪j個點后,0~i 的收益最大值
    • 或者說成前i個點中刪j個數,保留i的最大收益
  • 按i來划分集合,可以划分為0~i-1,其中0就代表前0個點刪j個數,等價於不刪.
  • f[i][j]可以從f[u][?]轉移過來,我們對f[i][j]做一個轉換
    • 既然要刪j個數,可以先把后面[u+1,i-1]給刪了,這樣會刪除i-1-u個數
    • 然后再在前面[0,u]中刪j-(i-1-u)個數,此時u點和i點臨近,可加貢獻 w[a[u]][a[j]]
      故可以得到如下狀態轉移方程 f[i][j] = max(f[i][j],f[u][j-(i-u-1)]+w[a[u]][a[i]]);
const int N = 210;
int n, k, m;
int a[N];	 // 記錄元素
int w[N][N]; // w[i][j]表示i->j的收益
int f[N][N]; // f[i][j] 表示0~i-1中刪除j個點后,0~i的最大收益
void solve() {
	cin >> n >> k >> m;
	for (int i = 1; i <= m; ++i) cin >> a[i];
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n; ++j)
			cin >> w[i][j];
	memset (f, -0x3f, sizeof (f) );
	f[1][0] = 0; // init
	// 第1個點刪0個數保留1的收益為0
	for (int i = 1; i <= m; i ++ )
		for (int j = 0; j <= k; j ++ )    //j從0~k,不刪就是0
			for (int u = 1; u < i; ++ u)  //最多刪i-1個
				if (j >= i - u - 1)       //注意是>=,=的條件下就說明既可以把后面刪完,也可以直接分配到0~i中
					//故要計算狀態
					f[i][j] = max (f[i][j], f[u][j - (i - u - 1)] + w[a[u]][a[i]]);
	int ans = 0;
	for (int i = 0; i <= k; ++i) ans = max (ans, f[m][i]);
	cout << ans << '\n';
}

星期四 AcWing 3502. 不同路徑數

這道題,爆搜 + set去重即可

const int N = 10;
int n, m, k;
int e[N][N];
set<int>S;
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int res = 0;
void dfs(int sx, int sy, int u, int s) {
	if (u == k) {
		if (!S.count(s)) ++res, S.insert(s);
		return;
	}
	for (int i = 0; i < 4; ++i) {
		int x = sx + dx[i];
		int y = sy + dy[i];
		if (x < 1 || x > n || y < 1 || y > m)continue;
		dfs(x, y, u + 1, s * 10 + e[x][y]);
	}
}
void solve() {
	cin >> n >> m >> k;
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j)
			cin >> e[i][j];
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= m; ++j) {
			dfs(i, j, 0, e[i][j]);
		}
	cout << res;
}

星期五 AcWing 3510. 最長公共子序列 (Mid

const int N = 1e6 + 7;
int id[N], q[N];
void solve() {
    int n;
    cin >> n;
    memset(id, -1, sizeof(id));
    for (int i = 0, x; i < n; ++i) {
        cin >> x;
        id[x] = i;
    }
    int tt = 0;
    q[0] = -1;
    for (int i = 0, x; i < n; ++i) {
        cin >> x;
        int k = id[x];
        if (k == -1)continue;
        int l = 0, r = tt;
        while (l  < r) {
            int mid = l + (r + 1) >> 1;
            if (q[mid] < k)l = mid;
            else r = mid - 1;
        }
        q[r + 1] = k;
        tt = max(tt, r + 1);
    }
    cout << tt << '\n';
}

星期六 AcWing 3489. 星期幾 (Easy)

套公式,或者逐年累加

int Day(int y, int m, int d) {
    if (m == 1 || m == 2)  m += 12, y -= 1;
    return (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400 +
            1) % 7;
}
string D[] = {
    "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
};
string DD[] = {
    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
};

void solve() {
    int y, d, mm;
    string m;
    while ( cin >> d >> m >> y) {
        for (int i = 0; i < 12; ++i)
            if (m == D[i])cout << DD[(Day(y, i + 1, d))] << "\n";
    }
}

星期日 AcWing 3481. 階乘的和

using ll = long long;
int fact[20];//10!就大於1e6
int combin[4100];//存所有階乘能組合出來的數,0~10有11種階乘,2^11空間存儲
int m = 0;
void dfs(int u, int st) {
    if (u == 11) {
        int res = 0;
        for (int i = 0; i < 11; ++i) {
            if (st >> i & 1) {
                res += fact[i];
            }
        }
        combin[m++] = res;
        return;
    }
    dfs(u + 1, st);
    dfs(u + 1, st | 1 << u);
}
void solve() {
    fact[0] = 1;
    for (int i = 1; i <= 10; ++i) fact[i] = fact[i - 1] * i;
    dfs(0, 0);
    sort(combin, combin + m);
    //  m = unique(combin, combin + m) - combin; // 去重,可有可無
    int x;
    while (cin >> x, x >= 0) {
        int l = 1, r = m - 1;
        int mid = l + r >> 1;
        //二分查找預處理數組
        while (l < r) {
            mid = l + r >> 1;
            if (combin[mid] >= x) r = mid;
            else l = mid + 1;
        }
        cout << (combin[l] != x ? "NO\n" : "YES\n");
    }
}

Week 2

星期一 AcWing 3516. 最大面積 (Hard

第一眼看過去像二維前綴和問題,但實際要使用單調棧解決

下面給出 4 道相關知識點遞增的題目

830.單調棧 -> 131. 直方圖中最大的矩形 -> 152. 城市游戲 -> 3516. 最大面積


Y總視頻講解,建議直接空降 30 min

const int N = 2010;
char g[N][N];
int l[N], r[N], q[N];
int U[N], D[N], L[N], R[N];
int s[N][N];
int n, m;

int calc(int h[], int n) {
	h[0] = h[n + 1] = -1;
	int tt = 0;
	q[0] = 0;
	for (int i = 1; i <= n; i ++ ) {
		while (h[q[tt]] >= h[i]) tt -- ;
		l[i] = q[tt];
		q[ ++ tt] = i;
	}
	tt = 0;
	q[0] = n + 1;
	for (int i = n; i; i -- ) {
		while (h[q[tt]] >= h[i]) tt -- ;
		r[i] = q[tt];
		q[ ++ tt] = i;
	}
	int res = 0;
	for (int i = 1; i <= n; i ++ )
		res = max(res, h[i] * (r[i] - l[i] - 1));
	return res;
}
void init() { // 注意初始化別寫錯...
	for (int i = 1; i <= n; ++i) { // 枚舉行
		for (int j = 1; j <= m; ++j)
			if (g[i][j] == '1')s[i][j] = s[i - 1][j] + 1;
			else s[i][j] = 0;
		U[i] = max(U[i - 1], calc(s[i], m));
	}
	memset(s, 0, sizeof(s));
	for (int i = n; i; i--) { // 枚舉行
		for (int j = 1; j <= m; ++j)
			if (g[i][j] == '1')s[i][j] = s[i + 1][j] + 1;
			else s[i][j] = 0;
		D[i] = max(D[i + 1], calc(s[i], m));
	}
	memset(s, 0, sizeof(s));
	for (int i = 1; i <= m; i ++ ) { // 枚舉列
		for (int j = 1; j <= n; j ++ )
			if (g[j][i] == '1') s[i][j] = s[i - 1][j] + 1;
			else s[i][j] = 0;
		L[i] = max(L[i - 1], calc(s[i], n));
	}
	memset(s, 0, sizeof(s));
	for (int i = m; i; i -- ) { // 枚舉列
		for (int j = 1; j <= n; j ++ )
			if (g[j][i] == '1') s[i][j] = s[i + 1][j] + 1;
			else s[i][j] = 0;
		R[i] = max(R[i + 1], calc(s[i], n));
	}
}
void solve() {
	cin >> n >> m;
	for (int i = 1; i <= n; ++i)scanf("%s", g[i] + 1);
	init();
	int _;
	cin >> _;
	while (_--) {
		int x, y;
		cin >> x >> y, x++, y++;
		cout << max(max(U[x - 1], D[x + 1]), max(L[y - 1], R[y + 1])) << "\n";
	}
}

星期二 AcWing 3404. 誰是你的潛在朋友

按題意來,把看同一本書的人放進數組。

意外的簡單

void solve() {
    int n, m;
    cin >> n >> m;
    bool vis[n + 1] = {false};
    int b[n + 1];
    vector<int>a[m + 1];
    for (int i = 1; i <= n; ++i) {
        cin >> b[i];
        a[b[i]].push_back(i);
    }
    for (int i = 1; i <= n; ++i) {
        if (a[b[i]].size() == 1)cout << "BeiJu\n";
        else cout << a[b[i]].size() - 1 << "\n";
    }
}

星期三 AcWing 3483. 2的冪次方

這道題,本質是對在二進制下的1進行遞歸處理

int n;
string dfs(int n) {
    string str;
    for (int i = 20; i >= 0; --i) {
        int f = 1 << i;
        if (i > 2 and (n & f)) {
            str += "2(";
            str += dfs(i);
            str += ')';
            n -= f;
            if (n != 0) str += '+';
        } else if (i <= 2 and (n & f)) {
            if (i == 0)str += "2(0)";
            if (i == 1) str += "2";
            if (i == 2) str += "2(2)";
            n -= f;
            if (n != 0) str += '+';
        }
    }
    return str;
}
void solve() { while (cin >> n)cout << dfs(n) << "\n";}
// 簡化代碼
string dfs(int x) {
    if (!x)return "0";
    string ans = "";
    for (int j = 31; j >= 0; --j) {
        if ((x >> j) & 1) ans += (j == 1) ? "2+" : "2(" + dfs(j) + ")+";
    }
    return ans.substr(0, ans.size() - 1);
}
void solve() {
    int n;
    while (cin >> n)cout << dfs(n) << "\n";
}

星期五 AcWing 3333. K-優字符串

int Case = 1;
void solve() {
	int n, k, sum = 0;
	cin >> n >> k;
	string s;
	cin >> s;
	int l = 0, r = s.size() - 1;
	while (l < r) {
		if (s[l] != s[r])sum++;
		l++, r--;
	}
	cout << "Case #" << Case++ << ": " << abs(sum - k) << "\n";
}

Week 3

星期一 AcWing 3554. 二進制

解法一: 模擬,二進制累加,當存在溢出時,即最后 c = 1 時要多輸出一個 1

void solve() {
    string a, b;
    cin >> a, b = a;
    int c = 0;
    for (int i = 31; i >= 0; i -= 1) {
        int tmp  = (a[i] - '0') + c;
        if (i == 31)tmp++;
        a[i] = (tmp % 2) + '0';
        c = tmp / 2;
    }
    if (c) cout << c;
    cout << a << "\n";
    c = 0;
    for (int i = 31; i >= 0; i -= 1) {
        int tmp = (b[i] - '0') + c;
        if (i == 31 || i == 30)tmp++;
        b[i] = (tmp % 2) + '0';
        c = tmp / 2;
    }
    if (c)cout << c;
    cout << b << "\n";
}

解法二:轉換成 long long 計算

using ll = long long;
void f(ll n) {	
    if (n >> 32 & 1)cout << 1;//最大的32位加3會變成33位,檢查一下	
    for (int i = 31; i >= 0; i -= 1) {		
        if (n >> i & 1)cout << 1;		
        else cout << 0;	
    }	
    cout << "\n";
}
void solve() {	
    string s; cin >> s;	
    ll n = 0;	
    for (int i = 0; i < 32; ++i)		
        if (s[i] == '1')  
            n = n | (1ll << (31 - i));	
    f(n + 1), f(n + 3);
}

解法三:Python 不講武德

T = int(input())for _ in range(T):    
    n = int(input(),2)    
    print(bin(n+1)[2:].rjust(32, '0'))    
    print(bin(n+3)[2:].rjust(32, '0'))

星期二 AcWing 3565. 完美矩陣

using ll = long long;
const int N = 110;
ll a[N][N];
vector<int>e[N][N];
void solve() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)e[i][j].clear();
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            cin >> a[i][j];
            e[min(i, n - i + 1)][min(j, m - j + 1)].push_back(a[i][j]);
        }

    ll ans = 0;

    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j) {
            if (!e[i][j].size())continue;
            sort(e[i][j].begin(), e[i][j].end());
            int t = e[i][j][(e[i][j].size() + 1) / 2 - 1];
            for (int k = 0; k < e[i][j].size(); ++k)
                ans += abs(t - e[i][j][k]);
        }
    cout << ans << "\n";
}

星期三 AcWing 3574. 乘積數量

方案一:前綴和維護區間負數個數

看到求區間的問題,會想到前綴和優化

我們可以用前綴和維護 \([1,s_n]\) 區間內的負數個數(因為會影響乘積的正負號的只有負數)

則對於區間 \([s_l,s_r]=v\),若 \(v\) 是奇數,則表示該區間的乘積為負數,反之是正數

  • \(s_r−s_{l−1}\)為奇數,則必定是 \(s_r\)\(s_{l−1}\) 一奇一偶

  • \(s_r−s_{l−1}\)為偶數,則必定是 \(s_r\)\(s_{l−1}\) 都是偶數或都是奇數

於是我們可以從前往后便利一遍數組,求出前綴和分別為奇數和偶數的個數

然后是一個組合數的問題了,設前綴和為奇數的個數為 \(v_1\) ,前綴和為偶數的個數為 \(v_2\)

區間為正數的子區間個數為 \(C^1_{v1}+C^1_{v2}\)

區間為負數的子區間個數為 \(C^1_{v1}×C^1_{v2}\)

int n;
int s[N];
int s0, s1;
void solve() {    
    cin >> n;    
    s0 ++ ;    
    for (int i = 1; i <= n; ++ i) {        
        int x;        
        cin >> x;        
        s[i] = s[i - 1] + (x < 0);        
        if (s[i] & 1) ++ s1;        
        else ++ s0;    
    }    
    cout << (LL)s0 * s1 << " " << (LL)s0 * (s0 - 1) / 2 + (LL)s1 * (s1 - 1) / 2 << endl;
}

方案二:DP

DP[i] 表示以 i 結尾的區間有多少個含奇數個負數

  • 則若 xs[i] < 0,則接到 i - 1 含偶數個負數的區間上
  • 否則,則接到 i - 1 含奇數個負數的區間上

但容易發現 \(dp_i\) 僅和前一項相關,所以采用滾動數組

const int N = 2e5 + 10;
int a[N], c[2];
ll cnt0, cnt1;
void solve() {
    int n;  cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    int v = 1;
    c[v]++;
    for (int i = 1; i <= n; ++i) {
        if (a[i] < 0) v ^= 1;
        cnt0 += (ll)c[v];
        cnt1 += (ll)c[v ^ 1];
        c[v]++;
    }
    cout << cnt1 << " " << cnt0 << '\n';
}

星期四 AcWing 3580. 整數配對

沒什么好講的,排序,累加即可

void solve() {
    int n; cin >> n;
    int a[n + 1], cnt = 0;
    for (int i = 1; i <= n; ++i)cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i = 2; i <= n; i += 2)cnt += a[i] - a[i - 1];
    cout << cnt ;
}

星期五 AcWing 3583. 整數分組

先對數組按升序排序,然后記錄每個數符合條件的最左側點下標,然后再用DP優化

  • \(f(i,j) = max(f(i,j),f(L_i-1,j-1) + i - L[i] + 1)\)

輸出 \(f[n][k]\) 即可

const int N = 5e3 + 10;
int f[N][N], n, a[N], L[N], k;
void solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; ++i)cin >> a[i];
    sort(a + 1, a + 1 + n);
    for (int i =  1; i <= n; ++i) {
        int p = i;
        while (p > 1 && a[p - 1] >= a[i] - 5) p--;
        L[i] = p;
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= k; ++j)f[i][j] = f[i - 1][j];
        for (int j = 1; j <= k; ++j)
            f[i][j] = max(f[i][j], f[L[i] - 1][j - 1] + i - L[i] + 1);
    }
    cout << f[n][k] << "\n";
}

Week 4

星期三 AcWing 3617. 子矩形計數

簡單的前綴和累加

using ll = long long;
ll a[40001], b[40001], n, m, i, j, k, ans = 0;
void solve() {
    cin >> n >> m >> k;
    for (i = 0; i < n; i++) {cin >> a[i]; if (a[i]) a[i] += a[i - 1];}
    for (i = 0; i < m; i++) {cin >> b[i]; if (b[i]) b[i] += b[i - 1];}
    for (i = 1; i <= n; i++)
        if (k % i == 0) {
            ll u = i, v = k / i, x = 0, y = 0;
            for (j = 0; j < n; j++) if (a[j] >= u) x++;
            for (j = 0; j < m; j++) if (b[j] >= v) y++;
            ans += x * y;
        }
    cout << ans;
}

星期四 AcWing 3624. 三值字符串

利用雙指針維護最小長度

const int inf = 0x3f3f3f3f;
void solve() {
    string s; cin >> s;
    int cnt[4] = {0};
    int l = 0, ans = inf;
    for (int i = 0; i < (int)s.size(); ++i) {
        cnt[s[i] - '0']++;
        while (cnt[1] and cnt[2] and cnt[3]) {
            cnt[s[l] - '0']--;
            ans = min(ans, i - l + 1);
            ++l;
        }
    }
    cout << (ans == inf ? 0 : ans) << "\n";
}

星期五 AcWing 3629. 同心圓塗色

模擬即可,注意 PI 的取值

const double pi = 3.1415926535897932384626433832795;
bool cmp(int a, int b) {return a > b;}
void solve() {
    int n; cin >> n;
    int r[n];
    for (int i = 0; i < n; ++i)cin >> r[i];
    sort(r, r + n, cmp);
    double ans = 0.0;
    int i;
    for (i = 1; i < n; i += 2) {
        ans += pi * (r[i - 1] * r[i - 1] - r[i] * r[i]);
    }
    if (i == n)ans += pi * r[i - 1] * r[i - 1];
    printf("%.06lf", ans);
}

Week 5

星期一 AcWing 3636. 數組延伸

const int N = 1e5 + 10, mod = 1e9 + 7;
ll n, x;
ll a[N];
void solve() {
    cin >> n >> x;
    for (int i = 1; i <= n; ++i)cin >> a[i];
    ll sum = 0, psum = 0;
    //分別代表一開始的數組和,可以向外擴展最小次數的那個數之前的和
    int cnt = N;
    //最小向外拓展次數
    for (int i = 1; i <= n; ++i) {
        sum += a[i];
        int c = 0;
        for (int j = a[i]; j % x == 0; j /= x)c++;
        if (c < cnt)cnt = c, psum = sum - a[i];
    }
    //答案就是一開始的數組和加上向外拓展次數*數組和,再加上截止到向外拓展次數最小的那個數之前的和(到這個數開始,就不是完整的拓展了)
    cout << sum * (cnt + 1) + psum << endl;
}

星期二 AcWing 3646. 分水果

最少 (0,0,1) 、(0,1,0)、(1,0,0),至多 (1,1,1)

所以特判情況即可

void solve() {
    int a[3];
    for (int i = 0; i < 3; ++i)cin >> a[i];
    int ans = 0;
    if (a[0])ans++, a[0]--;
    if (a[1])ans++, a[1]--;
    if (a[2])ans++, a[2]--;

    sort(a, a + 3);
    if (a[2] and a[1])ans++, a[2]--, a[1]--;
    if (a[2] and a[0])ans++, a[2]--, a[0]--;
    if (a[0] and a[1])ans++, a[0]--, a[1]--;

    if (a[0] and a[1] and a[2])ans++;
    cout << ans << "\n";
}

星期三 AcWing 3655. 樓層

數學 or 模擬

void solve() {
    int n, x;
    cin >> n >> x;
    if (n <= 2)cout << 1 << "\n";
    else cout << (n - 2 + x - 1) / x + 1 << "\n";
    // cout << ((n-3)/x+2) << endl;
}

星期五 AcWing 3664. 數組補全

貪心

找比y小的個數,一定不能超過中位數位置,然后左置1,右置y

void solve() {
    int n, k, p, x, y, tot = 0, a, d = 0, i = 0, l, m;
    cin >> n >> k >> p >> x >> y;
    for (; i < k; tot += a, d += (a < y), i++)cin >> a;
    l = n / 2 - d < n - k ? n / 2 - d : n - k;
    m = n - k - l;
    if (l < 0 || tot + l + m * y > x)cout << -1;
    else {
        while (m--)cout << y << ' ';
        while (l--)cout << 1 << ' ';
    }
}

Week 6

星期一 AcWing 3672. 數組重排

i - a[i] != j - a[j]
等價於 i - j != a[i] - a[j]
只需要逆序排列即可

void solve() {
    int n; cin >> n;
    vector<int>a(n);
    for (int &x : a)cin >> x;
    sort(a.begin(), a.end(), greater<int>());
    for (int i = 0; i < n; ++i)cout << a[i] << " ";
    cout << '\n';
}

星期二 AcWing 3679. 素數矩陣

4 1 0 0 0 0 0 
0 4 1 0 0 0 0 
0 0 4 1 0 0 0
0 0 0 4 1 0 0 
0 0 0 0 4 1 0
0 0 0 0 0 4 1
1 0 0 0 0 0 4 
void solve() {
    int n; cin >> n;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (i == j)cout << 4 << " ";
            else if (j == i + 1) cout << 1 << " " ;
            else if (i == n - 1 && j == 0) cout << 1 << " ";
            else cout << 0 << " ";
        }
        cout << endl;
    }
}

星期三 AcWing 3686. 移動序列

定位區間,然后計算1,0個數

void solve() {
    int n;
    cin >> n;
    vector<int>a(n);
    int cnt1 = 0;
    for (int &x : a) {
        cin >> x;
        if (x == 1)cnt1++;
    }
    int i = 0, j = n - 1;
    while (a[i] == 0) i++; //第一個1的位置
    while (a[j] == 0) j--; //最后一個1的位置
    cout << j - i + 1 - cnt1 << '\n';
}

星期四 AcWing 3697. 回文子序列

注意:問的是回文子序列,不是子串。

長度大於等於3的回文子序列 等價於 兩個相等的元素位置之差大於1

所以:遍歷數組,找出兩個相等的元素。如果位置之差大於1就輸出 YES。

如果遍歷完數組,也沒找到,就輸出 NO。

當然也可以用哈希表記錄下元素出現的位置,在 \(O(N)\) 時間內過掉。這個方法可以看看其他題解。

void solve() {
    int n; cin >> n;
    vector<int>a(n);
    for (int &x : a)cin >> x;
    bool f = false;
    for (int i = 0; i < n and !f; ++i)
        for (int j = i + 1; j < n; ++j)
            if (a[i] == a[j] and j - i > 1) f = true;
    cout << (f ? "YES\n" : "NO\n");
}

Week 7

星期一 AcWing 3705. 子集mex值

通過維護兩個變量從0開始,如果有0、1、2、3...這樣的直接慢慢向上疊加

const int N = 1e5 + 100;
ll n, a[N];
void solve() {
    cin >> n;
    for (int i = 0; i < n; ++i)cin >> a[i];
    sort(a, a + n);
    ll m = 0, k = 0;
    for (int i = 0; i < n; ++i) {
        if (a[i] == m)m++;
        else if (a[i] == k)k++;
    }
    cout << m + k << endl;
}

星期二 AcWing 3711. 方格塗色

待補

const int N = 1e5+10;
int main(){
    int t; scanf("%d", &t);
    while (t--){
        int n, u, r, d, l;
        scanf("%d %d %d %d %d", &n, &u, &r, &d, &l);
        int top, bottom, right ,left;
        bool f = 0;
        top = bottom = right = left = 0;
        
		if(u == n) top = 2;
        else if(u == n-1) top = 1;
        
        if(r == n) right = 2;
        else if(r == n-1) right = 1;

        if(d == n) bottom = 2;
        else if(d == n-1) bottom = 1;

        if(l == n) left = 2;
        else if(l == n-1) left = 1;
        
//        printf("%d %d %d %d\n",top, bottom, right, left);

        for(int i = 0; i < 16; i++){
        	int a[4] = {0,0,0,0}, cnt = 0;
        	while(i>>cnt){
        		a[cnt] = (i>>cnt)&1;
        		cnt++;
			}
			if(a[0]+a[1] >= top && a[0]+a[1] <= u) 
			if(a[0]+a[2] >= left && a[0]+a[2] <= l)
			if(a[1]+a[3] >= right && a[1]+a[3] <= r)
			if(a[2]+a[3] >= bottom && a[2]+a[3] <= d)
			f = 1;
			
		}

        if(f) cout << "YES\n";
        else cout << "NO\n";
    }
}

星期三 AcWing 3720. 數組重排

因為對於每個 ai+bi 都要滿足 <=x 這個條件

我們只需要貪心的 使得每個和盡可能的小即可

所以對兩個數組 按升序 和 降序 sort 一下即可

void solve() {
    int n, x;
    cin >> n >> x;
    vector<int> A(n, 0), B(n, 0);
    for (int i = 0; i < n; ++i)
        cin >> A[i];
    for (int i = 0; i < n; ++i)
        cin >> B[i];
    sort(A.begin(), A.end());
    sort(B.begin(), B.end(), greater<int>());
    bool ok = true;
    for (int i = 0; i < n; ++i)
        if (A[i] + B[i] > x)
            ok = false;
    cout << (ok ? "Yes" : "No") << endl;
}

星期四 AcWing 3725. 賣罐頭

math

ll _, n, x;
void solve() {
    ll l, r;
    cin >> l >> r;
    ll a = r + 1;
    if (l % a >= (a + 1) / 2) cout << "YES\n";
    else cout << "NO\n";
}

星期五 AcWing 3729. 改變數組元素

int arr[200001];
int res[200001];
void solve() {
    int n, i, mn = 1e9;
    cin >> n;
    for (i = 1; i <= n; i++) cin >> arr[i];
    for (i = n; i >= 1; i--) {
        mn = min(mn, i - arr[i]);
        res[i] = (mn < i);
    }
    for (i = 1; i <= n; i++) cout << res[i] << " ";
    cout << endl;
}

Week 8

星期一 AcWing 3730. 尋找序列

由於題目保證 \(a_i \not= b_i \not = c_i\)所以直接逐位判斷選什么即可,時間復雜度 \(\mathcal{O}(n)\)

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++)  cin >> a[i];
    vector<int> b(n);
    for (int i = 0; i < n; i++)  cin >> b[i];
    vector<int> c(n);
    for (int i = 0; i < n; i++)  cin >> c[i];
    vector<int> p(n, -1);
    for (int i = 0; i < n; i++) {
        p[i] = a[i];
        if (p[i] == p[(i + 1) % n] || p[i] == p[(i + n - 1) % n]) {
            p[i] = b[i];
            if (p[i] == p[(i + 1) % n] || p[i] == p[(i + n - 1) % n]) {
                p[i] = c[i];
            }
        }
    }
    for (int i = 0; i < n; i++) {
        if (i > 0) cout << " ";
        cout << p[i];
    }
    cout << '\n';
}

星期二 AcWing 3731. 序列湊零

ll _, n;
void solve() {
    cin >> n;
    int a[n + 1];
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int i = 0; i < n; i += 2) cout << a[i + 1] << ' ' << -a[i] << ' ';
    cout << endl;
}

星期三 AcWing 3732. 矩陣復原

#include <bits/stdc++.h>
#define x first
#define y second
using namespace std;
using ll = long long;
typedef pair<int, int> PII;
const int N = 510, M = N * N;
int n, m, k;
int g[N][N];
PII pos[M];
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= m; ++ j) {
            int x;
            cin >> x;
            pos[x].y = j;
        }
    }
    for (int i = 1; i <= m; ++ i) {
        for (int j = 1; j <= n; ++ j) {
            int x;
            cin >> x;
            pos[x].x = j;
        }
    }
    for (int i = 1; i <= n * m; ++ i) {
        auto &p = pos[i];
        g[p.x][p.y] = i;
    }
    for (int i = 1; i <= n; ++ i) {
        for (int j = 1; j <= m; ++ j) {
            cout << g[i][j] << " ";
        }
        cout << endl;
    }

}
int main() {
    ios::sync_with_stdio(false), cin.tie(nullptr);
    int _; for (cin >> _; _--;) solve();
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM