AcWing 每日一题

本篇解题记录题源来自 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 << '
';
}

星期四 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 << '
';
}

星期六 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))] << "
";
    }
}

星期日 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
" : "YES
");
    }
}

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])) << "
";
	}
}

星期二 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
";
        else cout << a[b[i]].size() - 1 << "
";
    }
}

星期三 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) << "
";}
// 简化代码
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) << "
";
}

星期五 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) << "
";
}

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 << "
";
    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 << "
";
}

解法二:转换成 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 << "
";
}
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 << "
";
}

星期三 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 << '
';
}

星期四 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] << "
";
}

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) << "
";
}

星期五 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 << "
";
}

星期三 AcWing 3655. 楼层

数学 or 模拟

void solve() {
    int n, x;
    cin >> n >> x;
    if (n <= 2)cout << 1 << "
";
    else cout << (n - 2 + x - 1) / x + 1 << "
";
    // 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 << '
';
}

星期二 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 << '
';
}

星期四 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
" : "NO
");
}

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
",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
";
        else cout << "NO
";
    }
}

星期三 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
";
    else cout << "NO
";
}

星期五 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 ot= b_i ot = 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 << '
';
}

星期二 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;
}

The desire of his soul is the prophecy of his fate
你灵魂的欲望,是你命运的先知。

原文地址:https://www.cnblogs.com/RioTian/p/14761145.html