2.13比赛总结

T1

题目:汇编语言(Assembly Language)是任何一种用于电子计算机、微处理器、微控制器
或其他可编程器件的低级语言,亦称为符号语言。在本题中,你只需要处理 NNN 个汇编指令,每个指令都会对变量 aaa 进行一些操作,在所有指令执行完毕后,你需要输出变量 aaa 的值。
变量 aaa 的初始值为 000。本题给出的汇编指令仅有4种:

  • inc:inc a 表示给变量a的值加1。
  • dec:dec a 表示给变量a的值减1。
  • add:add a,x 表示给变量a的值加x。
  • sub:sub a,x 表示给变量a的值减x。

很水的一道题,轻轻松松 AC 了,也不知道为什么我们机房里那么多人 WA。

T2

题目:在本场演出中,你一共需要敲击 NNN 次,每次敲击都有一定的精彩度 viv_ivi,整场演出的总精彩度每次敲击精彩度的总和。为了使演出更有感染力,你会选择 KKK 次敲击进行重击,但是这会导致该次敲击的精彩度降低,变为 vi×pi%v_i\times p_i\%vi×pi%,其中 0≤pi≤1000\le p_i\le1000pi100。你需要合理安排在哪一次敲击进行重击,使得整场演出的总精彩度最大,输出该最大值。总精彩度最大时,可能会有不同选择重击的方式,对于某些数据你还需要输出该总方案数。

知识点:贪心、组合数学。

很简单的一道题,只需要求出每次中级精彩度降低了多少,然后从小到大排个序就行了,方案数就是个组合数学,但因为精度问题考场上只拿了 80pts80pts80pts,结果下来一改就 AC,我真想骂这个精度问题。(关键在于我改前和改后感觉差不多)

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct drum{
    int id;
    double x;
}b[500006];
int n,k,m,a[500006],p[500006],fac[26];
double ans;
map<double,int>mp;
bool cmp(drum x,drum y)
{
    return x.x<y.x;
}
int C(int x,int y)
{
    fac[0]=1;
    for(int i=1;i<=19;i++)
    {
        fac[i]=fac[i-1]*i;
    }
    return fac[y]/fac[x]/fac[y-x];
}
signed main()
{
    // freopen("drum.in","r",stdin);
    // freopen("drum.out","w",stdout);
    cin>>n>>k>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        ans+=a[i]*1.0;
    }
    for(int i=1;i<=n;i++)
    {
        cin>>p[i];
        b[i].id=i;
        b[i].x=a[i]*1.0-(a[i]*1.0*p[i])/100;
    }
    sort(b+1,b+n+1,cmp);
    for(int i=1;i<=k;i++)
    {
        ans-=b[i].x;
    }
    printf("%0.5lf",ans);
    if(m)
    {
        int sum=0,sum2=0;
        for(int i=1;i<=n;i++)
        {
            if(b[i].x==b[k].x)
            {
                sum++;
            }
        }
        for(int i=k;i>=1;i--)
        {
            if(b[i].x==b[k].x)
            {
                sum2++;
            }
        }
        cout<<endl<<C(sum2,sum);
    }
    return 0;
}

T3

题目:这个网络中一共有 NNN 个节点,有 MMM 条线路,每条线路传输信息需要一定的时间 wiw_iwi。现在有 QQQ 个用户,每个用户都有一个类型的请求 RiR_iRi 和自己所在的节点 PiP_iPi,每个类型的请求需要发送到对应类型的高性能服务器才能被解析。为了节约成本,这 NNN 个节点中只有 KKK 个节点配置了高性能服务器,每台服务器都有一个类型 GiG_iGi 和所在的节点 FiF_iFi。每个用户的资源占用定义为用户发送请求到对应服务器所经过的最短时间。为了提高该网络的传输效率,你需要对用户发送信息的行为进行限制(即忽略一些用户的请求),使得在总资源占用不超过 TTT 的情况下,所有服务器解析用户请求的总数量最多。作为这个网络系统的管理员,你需要计算出所有服务器解析用户请求的总数量最多是多少。

知识点:最短路、贪心。

其实这道题很简单,没什么思维挑战性,就只是把匹配的服务器和用户之间求一下最短路,然后按从小到大的顺序把距离排序再贪心一下就行了,考试时一个地方 jjj 写成了 iii,挂了 70pts70pts70pts(π_π)。发现错误的那一刻我真的想骂人。

代码:

#include<bits/stdc++.h>
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
struct edge{
    int ed,s,nx;
}a[100006];
int n,m,q,k,t,x,y,s,cnt,p[10006],r[10006],f[26],g[26],head[100006],dis[10006],vis[10006];
vector<int>v,vv;
void add(int st,int ed,int s)
{
    a[++cnt].ed=ed;
    a[cnt].s=s;
    a[cnt].nx=head[st];
    head[st]=cnt;
}
void dijkstra(int x)
{
    priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>pq;
    memset(dis,INF,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[x]=0;
    pq.push(make_pair(dis[x],x));
    while(!pq.empty())
    {
        pair<int,int>p=pq.top();
        pq.pop();
        int v=p.second;
        if(vis[v])
        {
            continue;
        }
        vis[v]=1;
        for(int i=head[v];i;i=a[i].nx)
        {
            if(dis[a[i].ed]>dis[v]+a[i].s)
            {
                dis[a[i].ed]=dis[v]+a[i].s;
                pq.push(make_pair(dis[a[i].ed],a[i].ed));
            }
        }
    }
}
signed main()
{
//    freopen("protocol.in","r",stdin);
//    freopen("protocol.out","w",stdout);
    cin>>n>>m>>q>>k>>t;
    for(int i=1;i<=m;i++)
    {
        cin>>x>>y>>s;
        add(x,y,s);
        add(y,x,s);
    }
    for(int i=1;i<=q;i++)
    {
        cin>>p[i]>>r[i];
    }
    for(int i=1;i<=k;i++)//要从服务器去搜用户,不然会挂
    {
        cin>>f[i]>>g[i];
        for(int j=1;j<=q;j++)
        {
            if(g[i]==r[j])
            {
                v.push_back(p[j]);//就是这个地方写成了p[i]
            }
        }
        dijkstra(f[i]);
        for(auto j:v)
        {
            vv.push_back(dis[j]);
        }
        v.clear();
    }
    sort(vv.begin(),vv.end());
    int ans=0,sum=0;
    for(auto i:vv)
    {
        sum+=i;
        if(sum>t)
        {
            break;
        }
        ans++;
    }
    cout<<ans;
    return 0;
}

T4

题目:你可以和电子小狗进行 NNN 次互动,每次互动都会提升小狗对你的好感度 aia_iai。由于你非常忙,所以只能选择第 l,l+1,l+2,...,rl,l+1,l+2,...,rl,l+1,l+2,...,r 次互动,其中 1≤l≤r≤N1\le l\le r\le N1lrN。小狗对你的好感度为 xxx,初始值为 000。你会依次按照 l,l+1,l+2,...,rl,l+1,l+2,...,rl,l+1,l+2,...,r 的顺序进行互动。当然,好感度过高也会使小狗厌烦,定义 kkk 为小狗的好感度上限,当 k<xk\lt xk<x时,小狗对你的好感度 xxx 会直接清零。即对于你选择的每次互动,如果 x+ai≤kx+a_i\le kx+aik,那么 xxx 变为 x+aix+a_ix+ai,否则 xxx 变为 000。为了和小狗友好相处,你需要计算出有多少种不同选择 l,rl,rl,r 的方式,使得你选择的所有互动结束后,小狗对你的好感度 xxx 不为 000

知识点:动态规划、二分、前缀和。

这是我认为全场最有难度的一道题了(毕竟可是 T4)。我们来一步一步思考。

40pts

暴力搜索起点和终点,然后从起点到终点遍历一遍,按照上述方法看看是否满足要求,满足方案数就加一。

60pts(一个想法)

在上述方法上加以优化,把里面那层遍历的循环去掉,然后推导公式来判断是否成立(虽然我没推出来)。

100pts

要想拿到满分,我们就需要再优化。

因为数据很大,能通过的只有 O(n)O(n)O(n)O(nlog⁡2n)O(n\log_2n)O(nlog2n),再看题目要我们求方案数,求方案数不是组合数学就是 DP,这里一看就不好用组合数学(不信你可以试试),所以肯定用 DP。(这一步我想到了,但考场上没推出状态转移方程)

既然是 DP,我们就要想想 DP 的定义,一般情况下我们求啥设啥,所以 DP 的定义就是方案数,那我们的数组 dp[s] 就表示以 sss 为起点往后一共有多少种方案数。

我们再回过头来思考这么一件事:如果我们的和小于等于 kkk,是不会有事的,而只要一大于 kkk 就会清零,这条性质很特殊,所以我们就可以把整个区间分成一小段一小段的,每一段在经历了上述操作后的值都是 000,那我只要在这个段之内找点不就没事了,但找这个点又需要遍历一遍,这不就成了 O(n2)O(n^2)O(n2) 的了吗?

我们前面说过可以用前缀和,那我们这里为什么不也用前缀和呢?前缀和又具有单调性,就可以用二分去查找第一个大于 ai+ka_i+kai+k 的数,这之内的就都满足要求了,所以总的时间复杂度就是 O(nlog⁡2n)O(n\log_2n)O(nlog2n),那到这儿这道题就很简单了。假设我们找到的这个点的下标为 ttt,那 dp[s]dp[s]dp[s] 就可以被表示为:

dp[s]=dp[t]+t−s−1dp[s]=dp[t]+t-s-1dp[s]=dp[t]+ts1

代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,k,ans,a[200006],s[200006],dp[200006];
signed main()
{
    s[0]=1;
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=s[i-1]+a[i];//前缀和
    }
    for(int i=n;i>=0;i--)
    {
        int t=upper_bound(s+1,s+n+1,s[i]+k)-s;//二分查找
        dp[i]=dp[t]+t-i-1;//状态转移方程
    }
    for(int i=0;i<=n;i++)
    {
        ans+=dp[i];//总方案
    }
    cout<<ans;
    return 0;
}

总结:这次考试呢挂了 90pts90pts90pts,实属是不应该啊(我也不甘心啊,都怪我打代码打的太顺手了),最后一道题本来预计能拿 60pts60pts60pts 的,但是公式又推错了,希望下次能改进把。(不要再顺手了!!!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值