2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛正式赛) 【部分题题解】

现在才补,唉打的很烂。
前期还好1个小时过了5题感觉要金了,结果后面就再也没过了。
7题金,6题银,5题铜。又是一个铜首。
还是菜,感觉有机会拿金的。但是有些题确实我的掌握还是不熟。
求期望的那道题居然是原题一车的人过。
http://vj.saikr.com/contest/20/problems

Error【二分】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+10;
typedef long long int LL;
LL a[N],b[N],c[N],n;
bool check(int mid)
{
    
    
    vector<int>A; 
    A.push_back(a[0]-mid);
    for(int i=1;i<n;i++)
    {
    
    
         int l=max(a[i]-mid,1ll),r=a[i]+mid;
         if(r<A[i-1]) return false;
         A.push_back({
    
    max(l,A[i-1]+1)});
    }
    for(int i=0;i<n;i++)
    {
    
    
        int l=a[i]-mid,r=a[i]+mid;
        if(A[i]<l||A[i]>r) return false;
    }
    return true;
}
int main(void)
{
    
    
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    int l=0,r=1e9;
    while(l<r)
    {
    
    
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l;
    return 0;
}

树的果实【dfs序+莫队】

在这里插入图片描述
用dfs序将其转化成区间问题,然后莫队即可。
需要注意的是,这里并不是点的权值,而是边的权值。
我们将边的权值转化到点。例如: a->b 有c 故w[b]=c. 这样来转换。
在求的时候我们将多余计算的左端点删除后再存答案,然后在恢复原样即可。

#include<bits/stdc++.h> 
using namespace std;
typedef long long int LL;
const int N=1e5*2+10;
const int M=1e5*2+10;
int h[N],e[M],ne[M],idx;
int in[N],out[N],timestep;
int n,m,c;

void add(int a,int b)
{
    
    
	e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa)
{
    
    
	in[u]=++timestep;
	for(int i=h[u];i!=-1;i=ne[i])
	{
    
    
		int j=e[i];
		if(j==fa) continue;
		dfs(j,u);
	}
	out[u]=timestep;
}

LL res,pos[N],ans[N],cnt[N],a[N],w[N];//保存当前状态的值 
struct node{
    
    int l,r,id;}Node[N];
bool cmp(node a,node b)//排序 
{
    
    
	if(pos[a.l]==pos[b.l]) return a.r<b.r;
	return pos[a.l]<pos[b.l];
}
void add(int x)
{
    
    
	res-=(cnt[a[x]]*a[x])*(cnt[a[x]]*a[x]);
	cnt[a[x]]++;
	res+=(cnt[a[x]]*a[x])*(cnt[a[x]]*a[x]);
}
void sub(int x)
{
    
    
	res-=(cnt[a[x]]*a[x])*(cnt[a[x]]*a[x]);
	cnt[a[x]]--;
	res+=(cnt[a[x]]*a[x])*(cnt[a[x]]*a[x]);
}
int main(void)
{
    
    
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    //如果编译开启了 C++11 或更高版本,建议使用 std::cin.tie(nullptr);
	memset(h,-1,sizeof h);
	cin>>n>>m>>c;
	for(int i=1;i<=n-1;i++)
	{
    
    
		LL u,v,c; cin>>u>>v>>c;
		add(u,v),add(v,u);
		w[v]=c;
	}
	dfs(1,-1);
  	int len=sqrt(n);//分块 
	for(int i=1;i<=n;i++) pos[i]=i/len;//分块 
	for(int i=1;i<=n;i++) a[in[i]]=w[i];
	sort(Node+1,Node+m+1,cmp);
	for(int i=1;i<=m;i++)
	{
    
    
		int u; cin>>u;
		Node[i]={
    
    in[u],out[u],i};
	}
	sort(Node+1,Node+m+1,cmp);
	int l=1,r=0;//这是一个闭的区间  
	//如果l=0,r=0 则此时是一个[0,0]区间,这样的话起始就有了一个区间 
	for(int i=1;i<=m;i++)
	{
    
    
		while(Node[i].l<l) add(--l);
		while(Node[i].r>r) add(++r);
		while(Node[i].l>l) sub(l++);
		while(Node[i].r<r) sub(r--);
		sub(l++);//删除左边多余计算的
		ans[Node[i].id]=res;
		add(--l);//恢复状态
	}
	for(int i=1;i<=m;i++) cout<<ans[i]<<'\n';
	return 0;
}

吃利息【签到】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
LL n,m,sum;
int main(void)
{
    
    
    cin>>m>>n;
    sum=m;
    for(int i=0;i<n;i++)
    {
    
    
        LL temp=sum/10;
        sum=sum+min(5ll,temp);
        sum+=5;
    }
    cout<<sum;
	return 0;
}

MP4【dfs】

在这里插入图片描述
灵感来自

#include<bits/stdc++.h>
using namespace std;
int n,sum;
void dfs(int l, int r, int k)
{
    
    
    if (r > n) r = n;//过界了
    for (int i = l; i <= r; i++)
    {
    
    
        if (i != l && i % 10 == 0) return;//该位枚举完了
        sum++;
        if (sum <= k)
        {
    
    
            printf("%lld.mp4\n", i);
            if (sum == k)
                return;
        }
        if (i * 10 <= n) dfs(i * 10, i * 100 - 1, k);
    }
    return;
}
int main()
{
    
    
    cin>>n;
    dfs(1, 9, 50);
    return 0;
}

展览【线性基】

在这里插入图片描述
线性基板子题。

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
long long n, p[N], a[N], cnt;
void add(long long v)
{
    
    
    for(int i = 1; i <= cnt; i++)
        v = min(v, v ^ p[i]);

    if(v)
    {
    
    
        p[++cnt] = v;
        sort(p + 1, p + cnt + 1, greater<long long>());
    }
}
long long query_max()
{
    
    
    long long v = 0;
    for(int i = 1; i <= cnt; i++) v = max(v, v ^ p[i]);
    return v;
}
int main(void)
{
    
    
    cin >> n;
    for(int i = 1; i <= n; i++) scanf("%lld", a + i), add(a[i]);
    cout<<query_max();
}

礼物【签到】

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*5+10;
LL n,m,t,sum;
int a[N];
int main(void)
{
    
    
    cin>>n;
    for(int i=0;i<n;i++) cin>>a[i];
    sort(a,a+n);
    cout<<a[n-1];
	return 0;
}

看错题【线段树】

在这里插入图片描述
找规律的题。题目给的是满二叉树。

#include<bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e5*4+10;
LL sum=0;
int main()
{
    
    
	//cout<<(8*36)+(4*10)+(4*26)+ (2*3)  +(2*7) + (2*11)+ (2*15)+(1+2+3+4+5+6+7+8)<<'\n';//原来     540
    //cout<<(8*48)+(4*22)+(4*26)+ (2*11) +(2*11)+ (2*11)+ (2*15)+(5+6+7+4+5+6+7+8)<<'\n';//加3个点每个点加4 720
	//cout<<(8*40)+(4*14)+(4*26)+ (2*7)  +(2*7) + (2*11)+ (2*15)+(5+2+3+4+5+6+7+8)<<'\n';//加1个点每个点加4 600
    //说明一个点加60  60/4==15==(1<<deep)-1
  	//故加的值就是  点的个数 * 加的值 * (1<<deep)-1
	LL n,m; cin>>n>>m;
	LL deep=0;
	for(int i=1;i<=n;i++) 
	{
    
    
		int x; cin>>x;
		sum+=x;
	}
	while(n) n/=2,deep++;
	sum=sum*((1<<deep)-1);
	while(m--)
	{
    
    
		LL l,r,x; cin>>l>>r>>x;
		sum+=(r-l+1)*((1ll<<deep)-1)*x;
		cout<<sum<<'\n';
	}
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_46527915/article/details/124811889