2024 ICPC National Invitational Collegiate Programming Contest, Wuhan Site

赛时4题,和ggxxdd两个人打的

B:

K:

结论题,手玩观察出每四个都会为0一次,即可只分为四种情况做完。

F:

又是一个中位数必想到二分的题,虽然是第k分位数。。一开始方向全错(说明不应该没思考就分享思路的)但后来还是过了。

二分查找小于x的数小于k个必然不合法。因为矩阵每列有序,而在不同列上根据性质可以均摊一个n的复杂度,所以最终复杂度是O((nn+n)log(n*n))

#include <iostream>
using namespace std;
int n, k;

int query(int x) {
    int ret = 0;
    for (int i = 1, j = n ; i <= n; i++) {
        bool f = 0;
        j++;
        while(!f && j) {
            j--;
			if(!j)
                return ret;
            cout << "? " << i << " " << j << " " << x << endl;
            cout.flush();
            cin >> f;
        }
        ret += j;
    }
    return ret;
}

int main() {
    cin >> n >> k;
    int l = 1, r = n * n;
    while(l < r) {
        int mid = (l + r) / 2;
        if(query(mid) < n*n - k + 1) {
            l = mid + 1;
        }
        else {
            r = mid;
        }
    }
    cout << "! " << l << endl;
    return 0;
}

E:

看的时候其实是想到每次找树直径的中点了,但是下意识觉得自己不会动态维护直径没写。

维护直径是依靠这个结论:

对于直径两端点a,b和新加入点c,必有(a,c),(a,b),(b,c)三组之一为新的直径,所以只需要求两点距离的算法即可。

设t时刻直径为f(t), 一种情况需要跑完整棵树,答案为(),一种情况是f(t)<=((t-t0)*k取t最小,答案为t。取和即可。

D:

DP.
如何把一个不可递推问题转化为可递推问题?简化为一个可解决的问题,再观察这个问题与原问题之间的关系。
一开始我觉得不能dp但是答案确实是dp。
很容易想到的结论是最多变向一次。于是设g[x][t]为由x开始单向走t秒可吃到的最大值,然后发现如果在k秒后转向其实结果就是\(max(g[x-k][t-k],g[x+k][t-k])\)
这时候就需要斜线预处理两遍前缀最大值就可以得到答案了。斜线预处理看代码。但是这样空间过不了所以还要滚动优化一下。
还是比较难想的。。我也不知道这算什么dp类型/>?

#include <bits/stdc++.h> 
using namespace std;
#define int long long
const int maxn=5005;
int n, k;
int pre[maxn],F[maxn][maxn*2];
int mx1[2*maxn],mx2[2*maxn];
signed main(){
	cin>>n;int x;
	for(int i=1;i<=n;i++)cin>>x,pre[i]=pre[i-1]+x;
	for(int j=1;j<=n*2;j++){
		for(int i=n;i>=1;i--){
			int q=max(pre[i]-pre[max(i-j-1,1LL*0)],pre[min(i+j,n)]-pre[i-1]);
			mx1[i]=max(q,mx1[i-1]);
			F[i][j]=max(F[i][j],mx1[i]);
		}
	}
	for(int j=1;j<=n*2;j++){
		for(int i=1;i<=n;i++){
			int q=max(pre[i]-pre[max(i-j-1,1LL*0)],pre[min(i+j,n)]-pre[i-1]);
			mx2[i]=max(q,mx2[i+1]);
			F[i][j]=max(F[i][j],mx2[i]);
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++){
		int res=0;
		for(int j=1;j<=2*n;j++){
			//cout<<F[i][j]<<' ';
			res^=(j*F[i][j]);
		}
	//	cout<<endl;
		res+=i;
		ans^=res;
	}
	cout<<ans<<endl;
}

C:

队友一开始看错题的构造。。
我是想用两个数exgcd然后发现不会就没写了。
题解说是构造足够长的数列然后对于最后一部分exgcd即可。
于是我又回头去看exgcd求出xy值范围的证明,发现确实在大于一定值的时候就一定能找到xy正整数解。。。。唉唉

posted @ 2024-09-17 20:07  lyrrr  阅读(66)  评论(3)    收藏  举报