2021-2022年度第三届全国大学生算法设计与编程挑战赛(冬季赛)题解(7道题)

只有:B,D,E,G,I,K,L

正文

B:题目链接  Error

题目:

思路:二分

二分给出一个d,先考虑第一个数,让第一个数 r 为max(a[1]-d,0)

而且a[i]太小就直接返回NO,也就是 if( a[i]+d < r+1) return 0,如果a[i]很大,r也会很大,这样就是不利于后面的判断,但是仍然合法(就是不会直接返回 0)

考虑r的更新,因为递增,r最小为 r+1。因为差值小于d,r最小为 a[i]-d ,所以 r=max(r+1,a[i]-d);

int check(int d){
    int r=max(0,a[1]-d);        //题意给的是正整数,应该是max(1,a[1]-d),数据估计没卡这点
    fo(2,n){
        if(a[i]+d<r+1) return 0;
        r=max(r+1,a[i]-d);
    }
    return 1;
}

总代码:

#include<iostream>
#include<algorithm>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 1000005
int n;
int a[M];
int check(int d){
    int r=max(0,a[1]-d);
    fo(2,n){
        if(a[i]+d<r+1) return 0;
        r=max(r+1,a[i]-d);
    }
    return 1;
}
int main()
{
    cin>>n;
    fo(1,n) cin>>a[i];
    int l=1,r=1e9,ans=-1;
    while(l<=r){
        int mid=(l+r)/2;
        if(check(mid)){
            r=mid-1;
            ans=mid;
        }
        else l=mid+1;
    }
    cout<<ans<<endl;
    return 0;
}

 D:题目链接  树的果实

 题目:

思路: 树的dfs序+莫队

这题属实是没想到出个莫队,想到莫队的话难度不是很大,树遍历dfs序使一个点的子树成为连续的区间。

查询一个节点的子树值,就是查询一个连续区间的值,用普通莫队就可以做出,细节就不多说了,因为这里和莫队模板题很接近了

总代码:

#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define ll long long
#define int long long
#define M 400010
#define ll long long
int n,m,k,s=0,v,i,j;
int res=0;
struct Node
{
    int id,l,r;
    bool operator<(const Node temp)const{
        if(l/v==temp.l/v) return r<temp.r;
        return l<temp.l;
    }
}x[M];
struct node
{
    vector<pair<int,int>>v;
}xx[M];
int a[M],ans[M],vis[M];
int in[M],out[M],cnt=0;
void dfs(int d,vector<pair<int,int>>&v,int pre)
{
    int l=v.size();
    in[d]=++cnt;
    a[cnt]=v[i].second;
    for(int i=0;i<l;i++){
        if(v[i].first!=pre){
            dfs(v[i].first,xx[v[i].first].v,d);
        }
    }
    out[d]=cnt;
}
void add(int d){
    vis[d]++;
    res+=d*d*(vis[d]*vis[d]-(vis[d]-1)*(vis[d]-1));
}
void del(int d){
    res+=d*d*(-vis[d]*vis[d]+(vis[d]-1)*(vis[d]-1));
    vis[d]--;
}
int solve(int l,int r){
    while(i<l) del(a[i++]);
    while(i>l) add(a[--i]);
    while(j<r) add(a[++j]);
    while(j>r) del(a[j--]);
    return res;
}
signed main()
{
    cin>>n>>m>>k;
    v=sqrt(n*1.0);
    for(int a,b,c,i=1;i<n;i++){
        scanf("%lld%lld%lld",&a,&b,&c);
        xx[a].v.push_back(make_pair(b,c));
        xx[b].v.push_back(make_pair(a,c));
    }
    dfs(1,xx[1].v,0);
    for(int i=1;i<=m;i++){
        int temp;
        scanf("%lld",&temp);
        x[i].l=in[temp]+1;
        x[i].r=out[temp];
        x[i].id=i;
    }
    sort(x+1,x+m+1);
    i=1,j=0,res=0;
    for(int i=1;i<=m;i++) ans[x[i].id]=solve(x[i].l,x[i].r);
    for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
    return 0;
}

 说过子树一定用dfs序,过程中还是想偏了

 E:题目链接  吃利息

题目:

思路:简单模拟

题意看懂问题就不大,大概是每回合两笔收入,一个是5,一个是n/10,而后者最多是5。用循环实现即可

#include<iostream>
#include<algorithm>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define dou double
#define EXP 1e-8
#define ll long long
#define M 1000005
int t;
ll n,m,sum=0;
ll a[M];
int main()
{
    cin>>n>>m;
    while(m--){
        n+=(5+min((ll)5,n/10));
    }
    cout<<n<<endl;
	return 0;
}

F:题目链接  Star

题目:

这题是最亏的,大概率用到极角排序求凸包,最后求凸包面积吧,但是思路只有时间复杂度为2^50的暴力搜索,可能再加点凸包封闭不再搜索的优化,太麻烦了码一半自己放弃了。

但是看完唯一的视频题解,样例怎么都没法过,大概思路就是贡献思维,一个边能被贡献上只有右边没有一个点可以理解,但是边贡献的面积是什么都没听懂。

枚举三角形要么多情况,要么少情况,以后有机会会了再更吧

G:题目链接  MP4

题目:

思路:思维+sort

首先字符后面.mp4其实是不影响顺序的,就是数字的字典序排序,n如果很大的话,比如n为100100。可以发现,前面的都是1,10,100,1000,....,100000,100001,100002,100003.....

也就是从s=1开始,每*10添加往后50个数字,s+0,s+1,s+2...s+50,将这些不多的字符串进行sort排序输出即可,也就是保证答案被收录,剩下的交给sort。

这是比赛时保证不WA的代码,再精简情况也是完全可以的

int s=1;
while(s<n){
    fo(0,55){
        if(s+i<s*10&&s+i<=n){        //添加可能为答案的数
            add(s+i);
        }
    }
    s*=10;
}

 总代码:

#include<bits/stdc++.h>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define ll long long
#define M 100005
int n,l=0;
string s[M];
void add(int d)
{
    l++;
    while(d){
        s[l]+='0'+d%10;
        d/=10;
    }
    reverse(s[l].begin(),s[l].end());
    s[l]+=".mp4";
}
int main()
{
    cin>>n;
    if(n<10000){
        fo(1,n){
            add(i);
        }
    }
    else{
        int s=1;
        while(s<n){
            fo(0,55){
                if(s+i<s*10&&s+i<=n){
                    add(s+i);
                }
            }
            s*=10;
        }
    }
    sort(s+1,s+l+1);
    fo(1,50){
        cout<<s[i]<<endl;
    }
    return 0;
}

  I:题目链接  展览

题目:

 

 思路:线性基

这题属实离谱,要是只选两个的话,妥妥的字典树

然而这是线性基的模板题,那就没什么好说的了,下面是网上搜的最短的代码,还是自己学一下这个算法比较好

总代码:

#include<cstdio>
using namespace std;
typedef long long ll;
const int N=50+5,Maxbit=50;
ll p[N+1];
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;++i){
        ll x;scanf("%lld",&x);
        for(int j=Maxbit;j>=0;--j){
            if(!((x>>j)&1)) continue;
            if(!p[j]) {p[j]=x;break;}
            x^=p[j];
        }
    }
    ll ans=0,t;
    for(int j=Maxbit;j>=0;--j){
        t=ans^p[j];
        if(t>ans) ans=t;
    }
    printf("%lld\n",ans);
}

   K:题目链接 礼物

题目:

思路:简单模拟

思路就是求最大值,sort或者挨个比较都行,签到题

总代码:

#include<iostream>
#include<algorithm>
using namespace std;
#define fo(a,b) for(int i=a;i<=b;i++)
#define inf 0x3f3f3f3f
#define dou double
#define EXP 1e-8
#define ll long long
#define M 1000005
int t;
int n;
int a[M];
int main()
{
    cin>>n;
    fo(1,n){
        cin>>a[i];
    }
    sort(a+1,a+n+1);
    cout<<a[n]<<endl;
	return 0;
}

    L:题目链接 看错题

题目:

思路:思维

这题代码不需要线段树的,但是不会线段树题意是很难懂的,要明白任何时候这个满线段树都是合法的线段树,即顶点=两个子点的和,加子点多少,顶点也加多少,但顶点仍是两子点和

那么所有子点往上走,路程和,也就是答案 =(所有子点和)*(2 ^ 层数-1)

 这个图的答案就是

1+3+10        +        2+3+10        +        3+7+10        +        4+7+10

1+2+3+4  就是所有子点和=10,(3+7)+(3+7)=所有子点和*2,10+10+10+10=所有子点和*4。

最后就是(所有子点和)*(1+2+4)=(所有子点和)*(2 ^ 层数-1)

层数是不变的,(2 ^ 层数-1)就= 2*n-1

所以只求所有子点和,那就很简单了,累加ans,每次变化  ans+=z*(y-x+1);

scanf("%lld%lld%lld",&x,&y,&z);
ans+=z*(y-x+1);

总代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define M 1000005
#define lowbit(a) ((a)&(-a))
#define ll long long
ll n,m,a;
ll ans=0;
int main()
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a);
        ans+=a;
    }
    for(int i=1;i<=m;i++)
    {
        ll x,y,z;
        scanf("%lld%lld%lld",&x,&y,&z);
        ans+=z*(y-x+1);
        printf("%lld\n",ans*(n*2-1));
    }
    return 0;
}

 最后

可以发现前面的是思维,这个是比较接近正式赛的。后面的算法题就很多了,大多是偏算法模板题的。

  • 9
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
根据引用的信息,本题的解题思路是建立平纹织物整体热导率与单根纤维热导率之间关系的数学模型。在附件2的实验样品参数条件下,测得了平纹织物的整体热导率。因此,我们需要考虑纤维传热和空隙间的气体传热。 首先,我们可以根据附件1中的信息,假设纤维表面温度为热源侧的温度。然后,考虑到对流换热的影响,我们需要确定织物表面的对流换热系数。根据引用的信息,假设织物表面的对流换热系数为50 W/(m2K)。 接下来,我们可以根据引用中的信息,考虑织物的基础结构参数对导热性能的影响。这些参数包括纤维弯曲角度、织物厚度、经密和纬密等。在本题中,假设任意单根纤维的垂直切面为圆形,织物中的每根纤维始终为一个有弯曲的圆柱。经纱和纬纱的弯曲角度范围为10° ≤ e ≤ 26.565°。 最后,根据附件2的实验样品参数条件下测得的平纹织物的整体热导率,我们可以建立平纹织物整体热导率与单根纤维热导率之间的关系的数学模型。这个模型将有助于我们进一步研究和预测不同织物结构参数对热导性能的影响。 综上所述,解题思路包括考虑纤维传热和空隙间的气体传热、确定织物表面的对流换热系数、考虑织物的基础结构参数对导热性能的影响,并建立平纹织物整体热导率与单根纤维热导率之间的关系的数学模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

int 我

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值