前言

十分抱歉由于T4一个括号没写对和T2的大数据出锅给大家带来了不好的比赛体验。

赛后总结

  • A (82/189) 满分: 100分
  • B (20/137) 满分: 100分
  • C (6/75) 满分: 100分
  • D (3/43) 满分: 100分

COOL

给你一个字符串,求其子序列cooooooooooooooooooooooooll 位置的最小值。

30pts

由于 因此显然不存在,输出 -1 即可。

100pts

可以先找第一个 c 的位置,然后再找第 o 的位置 ,最后找一个 l 的位置即可。

代码如下

#include<bits/stdc++.h>

using namespace std;

const int maxn=100100;

char s[maxn];
int n,cpos,ocnt,opos,lpos;

int main()
{
    scanf("%s",s+1);
    n=strlen(s+1);
    //find c
    for(int i=1;i<=n;i++)
    {
        if(s[i]=='c') {cpos=i;break;}
    }
    if(!cpos) 
    {
        cout<<-1<<'\n';
        return 0;
    }
    for(int i=cpos;i<=n;i++)
    {
        if(s[i]=='o') ocnt++;
        if(ocnt==24) {opos=i;break;}
    }
    if(ocnt!=24) 
    {
        cout<<-1<<'\n';
        return 0;
    }
    for(int i=opos;i<=n;i++)
    {
        if(s[i]=='l') {cout<<i<<'\n';return 0;}
    }
    cout<<-1<<'\n';
}

food

个物品,每个物品可以选择 个,单价为 。并且买 个会自动变成 个,价格为 。买多了会有惩罚。

30pts

显然我们会买 个 。将数组排序取前 大即可

50pts

就相当于买了只能买

相当于买 或者单买 。

表示在第 个食堂,打了 个菜品花费。

对于 转移即为

对于 转移即为

100pts

继续枚举,对

其中

注意转移时代码的细节

#include<bits/stdc++.h>

using namespace std;

const int maxn=1010;

int f[maxn][maxn],n,x,q;
int b[maxn],a[maxn],cnt;

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>x>>q;
    memset(f,0x3f,sizeof(f));
    for(int i=0;i<=n;i++) f[i][0]=0;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i]>>b[i];
        for(int j=1;j<=x+n;j++)
        {
            for(int k=1;k<=min(j,b[i]-1);k++)
            {
                f[i][j]=min(f[i-1][j-k]+a[i]*k,min(f[i][j],f[i-1][j]));
            }
            if(j>=b[i]+1) f[i][j]=min(f[i-1][j-b[i]-1]+b[i]*a[i],min(f[i][j],f[i-1][j]));
        }
    }
    int ans=0x3f3f3f3f;
    for(int i=x;i<=x+n;i++)
    {
        ans=min(ans,f[n][i]+(i-x)*q);
    }
    cout<<ans<<'\n';
    return 0;
}

latex

本题分为两部分

表达式计算

假设表达式字符串 t ,其被复制结果为 t+'*'+t

由于乘法有一个优先级问题,因此我们用一个栈。

当运算符为加法时,将其放入栈顶部。

当为乘法是,取出栈顶元素,与其相乘再放入栈顶。

高精度计算

考虑到竖式计算即可。

考虑倒序,即 代表最低位,则 中,对每一对

但是每个人高精度写法不同,以下代码仅供参考。

#include<bits/stdc++.h>

using namespace std;

const int maxn=34100;
const int basew=201;

struct bigint{

    int a[220]={0};
    
}v[maxn];

map <string,bigint> val;
int f[maxn],n,cnt;

bigint operator+(const bigint &a,bigint &b)
{
    bigint ans;
    for(int i=basew;i>=1;i--)
    {
        ans.a[i]+=a.a[i]+b.a[i];
        if(ans.a[i]>=10) 
        {
            ans.a[i-1]+=ans.a[i]/10;
            ans.a[i]%=10;
        }
    }
    return ans;
}

bigint operator*(const bigint &a,bigint &b)
{
    bigint ans;
    for(int i=basew;i>=1;i--)
    for(int j=basew;j>=1;j--)
    {
        if(basew-(basew-i)-(basew-j)<=0) continue;
        ans.a[basew-(basew-i)-(basew-j)]+=a.a[i]*b.a[j];
    }
    for(int i=basew;i>=1;i--)
    {
        if(ans.a[i]>=10) ans.a[i-1]+=ans.a[i]/10,ans.a[i]%=10;
    }
    return ans;
}

bigint getval(string &t)
{
    stack <pair<bigint,char> > s;
    //记录表达式出现的位置
    vector<int> p;
    int tn=t.size();
    for(int i=0;i<tn;i++)
    {
        if(t[i]=='+'||[i]=='*') p.push_back(i);
    }
    string nowver=t.substr(0,p[0]);
    p.push_back(tn);
    s.push({val[nowver],'+'});
    for(int i=0;i<p.size()-1;i++)
    {
        nowver=t.substr(p[i]+1,p[i+1]-p[i]-1);
        if(t[p[i]]=='*') 
        {
            bigint x=s.top().first*val[nowver];
            char f=s.top().second;
            s.pop();
            s.push({x,f});
        }
        else
        {
            bigint x=val[nowver];
            s.push({x,p[i]});
        }
    }
    bigint ans;
    while(!s.empty())
    {
        bigint x=s.top().first;
        char f=s.top().second;
        s.pop();
        ans=ans+x;
    }
    return ans;
}

int getf(int x)
{
    if(x==f[x]) return x;
    return f[x]=getf(f[x]);
}

void init()
{
    for(int i=1;i<=10000;i++) f[i]=i;
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        string tmp,v;
        bigint vt;
        cin>>tmp>>v;
        int tn=v.size();
        for(int j=tn-1;j>=0;j--)
        {
            vt.a[basew-(tn-1-j)]=v[j]-'0';
        }
        val[tmp]=vt;
    }
    string t;
    vector <int> eq;
    while(cin>>t)
    {
        if(t[0]=='$')
        {
            ++cnt;
            t=t.substr(1,t.size()-2);
            t=t+'*'+t;
            v[cnt]=getval(t);
        }
    }
    int flag=1;
    for(int i=1;i<=cnt;i++)
    {
        int flag=0;
        for(int j=1;j<=basew;j++)
        {
            if(v[i].a[j]) 
            {
                flag=1;
            }
            if(flag) cout<<v[i].a[j];
        }
        if(!flag) cout<<0;
        cout<<'\n';
    }
}

driver

考虑函数

当斜率小于 时,说明 显然这条路走不通。我们考虑走得通的情况,则斜率一定大于

换句话说,当斜率大于 带的油越多越能走。

当我们到终点时,假设之前最多加油为 油箱还会剩下 的油

20pts

枚举访问顺序即可。

40pts

一棵树的情况,直接bfs能走就走

50pts

如果带 油不可以,那么就得带

表示带 油走到这里的最短路即可。

100pts

表示带 油走到这里的最短路。

考虑转移,之前已经想到,带的油越多越能走。因此可以二分或者倒序扫描得到一条边要通过需要油的最小值。

这一条边在 油量时可以走通,那么可以有转移 否则必须先加油到

这里可以使用一个分层图最短路来做,第 层代表油量为 能走的边的子图。 即为最后的答案。

#include<bits/stdc++.h>

using namespace std;

const int maxn=310*210;

int dis[maxn],n,m,mino[3200],vis[maxn],ans;
// int mp[maxn][maxn]; 
int Omax; //最大油量
vector <pair<int,int>> G[310*210];
vector <tuple<int,int,int>> E;//存储初始权值

int nodeindex(int x,int w) //分层第w层的点编号
{
    return x+(w-1)*n;
}

void addedge(int x,int y,int dis,int f) //f=1 单向边 f=2 双向边
{
    G[x].push_back({y,dis});
    if(f==2) G[y].push_back({x,dis});
}  

void dijkstra(int st)
{
    memset(dis,0x3f,sizeof(dis));
    priority_queue<pair<int,int> > q;
    q.push({0,st});
    dis[st]=0;
    while(!q.empty())
    {
        int t=q.top().second;
        q.pop();
        if(vis[t]) continue;
        vis[t]=1;
        for(auto [u,k]:G[t])
        {
            if(dis[t]+k<dis[u])
            {
                dis[u]=dis[t]+k;
                q.push({-dis[u],u});
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>m>>Omax;
    for(int i=1,x,y,z;i<=m;i++)
    {
        cin>>x>>y>>z;
        E.push_back({x,y,z});
        // mp[x][y]=mp[y][x]=z;
    }
    for(int o=Omax,cnt=0;o;o--,cnt=0)
    for(auto [x,y,z]:E)
    {
        cnt++;
        //由于没有边权为0的边 因此从1开始
        if((1+(o/Omax))*z<=o)
        {
            if(o==1)
            {
                int xxx=1;
            }
            addedge(nodeindex(x,o),nodeindex(y,o),(1+(o/Omax))*z,2);
            mino[cnt]=o; //记录如果想走通这一条路至少需要加多少油
        }
        else
        {
            if(!mino[cnt]) continue;
            //否则想要过去,就必须跨层。
            addedge(nodeindex(x,o),nodeindex(y,mino[cnt]),(1+(mino[cnt]/Omax))*z,1);
            addedge(nodeindex(y,o),nodeindex(x,mino[cnt]),(1+(mino[cnt]/Omax))*z,1);
        }
    }
    dijkstra(1);
    ans=0x3f3f3f3f;
    for(int i=1;i<=Omax;i++)
    {
        ans=min(ans,dis[nodeindex(n,i)]+i);
    }
    cout<<ans<<'\n';
}

/*
3 2 100
1 2 10
2 3 1
*/