yuwj  

碎碎念:
近期一直板刷atcoder,前两个月因为一堆破事导致根本没有好好训练杭电,现在终于有点大块时间可以静下心来好好加训了
选最近得一场
虽然上个月末得时候vp和cf板刷给我整抑郁了差点

先看补题进度

由于上周五不重视杭电,所以跑去写作业了,结果就没有好好训练,罪该万死
那道唯一现场过的题目都是写完作业看了一下最后一分钟极限AC的QWQ,这种惊险刺激的感觉越多越好,这个多巴胺不少,质量也高~
1005没动,不知道为什么看到字符串就烦,所以跳了,然后两道看着像计算几何的也没动,感觉自己补不动就算了

1009

实际上是找最长相邻子序列

/*
ans = n - 最长上升相邻子序列长度
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

void solve()
{
    int n, ans = 0; cin >> n;
    vector<int> dp(n+1, 1), a(n+1);//dp[i]:以i数字结尾的最长上升子序列长度
    for(int i = 1; i <= n; i++) cin >> a[i];
    set<int> st;
    
    for(int i = 1; i <= n; i++)
    {
        int x = a[i];
        if(st.count(x-1)>0)dp[x] = dp[x-1]+1;
        st.insert(x);
    }

    ans = *max_element(dp.begin(), dp.end());
    cout << n - ans << '\n';
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t; cin >> t;while(t--)
    solve();return 0;
}

1002

马拉车板子
回文半径数组是核心

/*
性质:中心对称具有中心扩展性
Manachar算法,
回文半径数组

【扩展串】
【回文半径】:【回文半径数组】
从中心点出发,往左右两边扩展,
算上中心扩展出去的长度

【原始串长度】 = 回文半径长度 - 1
【真实串的终止位置】(到不了的) = 扩展回文串的终止下标/2

【回文覆盖右边界r】【回文中心c】

i没有被r包住,以i为中心直接扩展
i被r包住,对称点2*c - i的回文半径,在大区域回文内部,p[i] = p[2*c - i]
i被r包住,对称点2*c - i的回文半径,在大区域回文外部,p[i] = r - i
i被r包住,对称点2*c - i的回文半径,撞线大区域边界,r以内的范围不用再验证,从r之外的位置继续往外扩展
*/
#include <bits/stdc++.h>
using namespace std;
using ll = long long;

vector<int> manacher(vector<int> s0) {
    vector<int> s = {-1};
    for(auto val : s0)
    {
        s.push_back(val);
        s.push_back(-1);
    }

    int n = size(s);

	vector<int> d(n);
	for (int i = 0, l = 0, r = -1;i <= n - 1;++i) {
		int k = (i > r) ? 1 : min(d[l + r - i], r - i + 1);
		while ((0 <= i - k) && (i + k <= n - 1) && (s[i - k] + s[i + k] == s[i - k + 2] + s[i + k - 2])) {
			k++;
		}
		d[i] = k--;
		if (i + k > r) {
			l = i - k;
			r = i + k;
		}
	}
	return d;
}
void solve(){
    int n; cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; i++) cin >> a[i];

    auto d = manacher(a);

    ll ans = 0;
    for(auto x : d) ans += x/2;
    cout << ans << '\n';
}

int main(){
    ios::sync_with_stdio(0);cin.tie(0);
    int t; cin >> t;while(t--)
    solve();return 0;
}

1001

题意:
最小化等车时间
思路:
【期望DP】
【时间序枚举上一个的时间】
这个题目我还是第一次看到这样的期望计算的,期望等车时间 = 时间/2
题意看了半天都没理解这个期望是什么意思

实际上就是时间均匀分布,由于落到区间上任意点的概率是完全随机的,所以是平均分布
平均等车时间就是t/2,每一段的时间也就是d/2
期望就是sum(dd/2nt),答案就是最小化dd即可

所以这个时间序上怎么dp?
对于每个位置,枚举上一个到站点的时间,在操作次数内的最小值就ok了
嗯,就是题解那个意思

代码:

#include <iostream>
#include <cstring>
#define MULTI int _T; cin >> _T; while(_T--)
#define sqr(x) ((x) * (x))
using namespace std;

typedef long long ll;

const int N = 105;
const ll INFF = 0x3f3f3f3f3f3f3f3f;
template <typename T> bool chkmin(T &x, T y) {return y < x ? x = y, 1 : 0;}
template <typename T> bool chkmax(T &x, T y) {return y > x ? x = y, 1 : 0;}

ll t, n, m;
ll a[N];
ll dp[N][N][N];

int main() {
	MULTI {
		cin >> t >> n >> m;
		for (int i = 1;i <= n - 1;++i) {
			cin >> a[i];
		}

		memset(dp, 0x3f, sizeof dp);
		dp[0][0][0] = 0;
		for (int cur = 0;cur <= n * t;++cur) for (int lst = 0;lst <= cur;++lst) {
			for (int i = 1;i <= n - 1;++i) {
				ll cnt_op = abs(a[i] - cur);
				ll delta = sqr(cur - lst);
				if (i == n - 1) delta += sqr(n * t - cur);
				for (int j = cnt_op;j <= m;++j) {
					chkmin(dp[cur][i][j], dp[lst][i - 1][j - cnt_op] + delta);
				}
			}
		}

		ll ans = INFF;
		for (int cur = 0;cur <= n * t;++cur) {
			for (int j = 0;j <= m;++j) {
				chkmin(ans, dp[cur][n - 1][j]);
			}
		}
		cout << ans << endl;
	}
}

1010

时机连通块,atcoder有个加强版的
代码:

/*
将某个点给切下来之后,判断这张图是否仍然连通
由前i个顶点组成的图恰好由0,1,2...k这几个顶点组成

这个自然思路遇到的问题:
1.怎么切下来?
2.怎么判断这个图还是连通的?

前i个结点不通过更大的结点即可连通块

时刻并查集?
max(u,v) 大小是否 == k
*/
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;

struct DSU{
    int fa[N], sz[N];
    
    void init(int n){
        for(int i = 0; i <= n; i++)
        {
            fa[i] = i;
            sz[i] = 1;
        }
    }

    int find(int x){
        return fa[x] == x ? x : fa[x] = find(fa[x]);
    }

    void merge(int x, int y)
    {
        int rx = find(x), ry = find(y);
        if(rx == ry) return;
        if(sz[rx] < sz[ry]) swap(rx, ry);
        sz[rx] += sz[ry];
        fa[ry] = rx;
    }

    int getsz(int x){
        return sz[find(x)];
    }
};

void solve()
{
    int n, m; cin >> n >> m;
    n++,m;
    vector<vector<pair<int,int>>> G(n+1);

    for(int i = 0; i < m; i++)
    {
        int u, v; cin >> u >> v;
        u++,v++;
        G[max(u,v)].push_back({u,v});
    }
    DSU D; D.init(n);
    bool ans = 1;
    for(int k = 1; k <= n; k++)
    {
        for(auto [u,v] : G[k]) D.merge(u,v);
        //cout << D.getsz(1) << '\n';
        if(D.getsz(1) != k) ans = 0;
    }

    if(ans)printf("%d\n",1);
    else printf("%d\n",0);
}

int main()
{
    int t; cin >> t;
    while(t--)
    {
        solve();
    }
    return 0;
}

1008

按照大小排序出现顺序
用0段和相邻1段作为可选区间,计数就完了
然后有个二维区间前缀和
代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e3 + 10;
int b[N], s[N][N];

void inc(int xl, int xr, int yl, int yr) {
	s[xl][yl]++;
	s[xl][yr + 1]--;
	s[xr + 1][yl]--;
	s[xr + 1][yr + 1]++;
}


void solve()
{
    int n, q; cin >> n >> q;
    vector<pair<int,int>> a(n+1);
    for(int i = 1; i <= n; i++){
        int val;
        cin >> val;
        a[i] = {val, i};
    }

    sort(a.begin()+1, a.end());
    fill(b, b+n+1,1);
    memset(s,0,sizeof s);

    for(int i = 1; i <= n; i++)
    {
        int pos = a[i].second;
        b[pos] = 0;
        int l0 = pos; while(l0>1 && b[l0-1] == 0) l0--;
        int r0 = pos; while(r0<n && b[r0+1] == 0) r0++;

        int l1 = r0+1, r1 = l1;
        while(r1<n && b[r1+1]==1) r1++;

        inc(l0,pos,l1,r1);
    }

    for (int i = 1;i <= n;++i) {
		for (int j = 1;j <= n;++j) {
			s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
		}
	}

	for (int i = 1;i <= q;++i) {
		int l, r;
		cin >> l >> r;
		cout << s[l][r] << "\n";
	}
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t; cin >> t; while(t--)
    solve();return 0;
}

1004

分类讨论?反正就是用了的,然后剩下的怎么玩,就是这样,结束

#include <bits/stdc++.h>
using namespace std;

void solve()
{
    int n, m, t, ans; cin >> n >> m;
    if(m == 1){
        cout << n << '\n';
    }else if(n <= m){
        cout << 1 << '\n';
    }else{
        t = m/2 + 1;
        ans = n/t;
        if(n % t !=0 && (n%t > (m-t))) ans++;
        cout << ans << '\n';
    }
}

int main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t; cin >> t; while(t--)
    solve();return 0;
}
posted on 2025-05-17 07:04  xiaowang524  阅读(10)  评论(0)    收藏  举报