KunOI Round 1 题解

A 唱

按照题意模拟即可。别见祖宗。

$\texttt{code}$
#include<bits/stdc++.h>
using namespace std;
int main(){
    long long n,maxn=0;
    cin>>n;
    for(long long x,y;n--;){
        cin>>x>>y;
        maxn=max(maxn,x*y);
    }
    cout<<maxn;
}

B 跳

考虑当前石头是从哪里跳过来的,显然有状态转移方程 \(f_i=\min\limits_{j=i-k}^{i-1}(f_j+|a_i-a_j|)\),注意 \(j\) 的边界以及 \(f\) 的初始化 \(f_1=0\),其余为 \(\infty\)。别见祖宗。

扩展:若 \(n,k\) 同阶,考虑使用权值树状数组套动态开点线段树的方法,可以做到 \(\mathcal{O}(n\log^2n)\),就是要注意一下空间。

$\texttt{code}$
#include<bits/stdc++.h>
#define int long long
#define N 250005
using namespace std;
int n,k,a[N],f[N];
signed main(){
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    cin>>n>>k;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        f[i]=1e18;
    }
    f[1]=0;
    for(int i=2;i<=n;++i){
        for(int j=max(i-k,1ll);j<i;++j){
            f[i]=min(f[i],f[j]+abs(a[i]-a[j]));
        }
    }
    cout<<f[n];
}

C rap

不难发现当 \(\gcd(i,j)=1\) 时,\(\text{rap}(i\cdot j)=\text{rap}(i)\cdot \text{rap}(j)\),类似于 \(\varphi\) 一样线性筛再预处理前缀和即可。

其实这个 \(\text{rap}\) 函数就是伟大的莫比乌斯 \(\mu\) 函数。

$\texttt{code}$
#include<bits/stdc++.h>
#define N 2500001
using namespace std;
int rap[N],l,r,T,p[N],sum[N];
bool no[N];
int main(){
    p[1]=sum[1]=1;
    for(int i=2;i<N;++i){
        if(!no[i]){
            rap[i]=-1;
            p[++p[0]]=i;
        }
        for(int j=1;j<=p[0]&&i*p[j]<N;++j){
            no[i*p[j]]=1;
            if(!(i%p[j])){
                rap[i*p[j]]=0;
                break;
            }
            rap[i*p[j]]=-rap[i];
        }
        sum[i]=sum[i-1]+rap[i];
    }
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&l,&r);
        printf("%d\n",sum[r]-sum[l-1]);
    }
}

D 篮球

\((u,v,w)\)\(u,v\) 之间有一条权值为 \(w\) 的边。 先建原图的双向边。

首先考虑没有改粉丝类型操作怎么做。套路地,第 \(i\) 种颜色建一个点 \(c_i\),连 \((u,c_{a_u},0)\)\((c_{a_u},u,x)\)。答案即为 \(s\) 到每个点的最短路。

现在加上改粉丝类型的操作,可以类似地再建一个点 \(T\),连 \((c_i,T,y)\)\((T,c_i,0)\)。答案即为 \(s\) 到每个点的最短路。

这里最短路使用的是 pb_ds pairing heap 优化的 Dijkstra,建议搭配 C++14(GCC 9) 使用。

$\texttt{code}$
#include<bits/stdc++.h>
#include<ext/pb_ds/priority_queue.hpp>
#define N 1000001
#define ll long long
using namespace std;
int n,m,s,k,a[N],tot,mp[N];
ll d[N],x,y;
bool vis[N];
struct edge{
    int v;
    ll w;
};
vector<edge>g[N];
struct node{
    int v;
    ll w;
    bool operator<(const node&p)const{
        return w>p.w;
    }
};
__gnu_pbds::priority_queue<node>q;
int main(){
    memset(d,0x3f,sizeof d);
    scanf("%d%d%d%d%lld%lld",&n,&m,&s,&k,&x,&y);
    tot=n;
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }
    for(int i=1,u;i<=k;++i){
        scanf("%d",&u);
        if(!mp[a[u]]){
            g[mp[a[u]]=++tot].push_back({0,y});
            g[0].push_back({tot,0});
        }
        g[u].push_back({mp[a[u]],0});
        g[mp[a[u]]].push_back({u,x});
    }
    for(int u,v;m--;){
        ll w;
        scanf("%d%d%lld",&u,&v,&w);
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    q.push({s,d[s]=0});
    while(q.size()){
        auto[t,f]=q.top();
        q.pop();
        if(vis[t]){
            continue;
        }
        vis[t]=1;
        for(auto[v,w]:g[t]){
            if(d[v]>f+w){
                q.push({v,d[v]=f+w});
            }
        }
    }
    for(int i=1;i<=n;++i){
        printf("%lld ",d[i]);
    }
}

集贤亭

私信负责人,分享你独特的见解!

具体流程:写好博客,私信负责人链接,负责人看到会回复并展示在这个版块。贡献者会有每人一坤分的报酬,若提出了新奇/吊打标程等启发性见解,会酌情增加报酬。

posted @ 2023-02-17 22:25  lzyqwq  阅读(72)  评论(0)    收藏  举报