Educational Codeforces Round 89 (Rated for Div. 2)

D.Two Divisors

#include<bits/stdc++.h>
using namespace std;


const int N=500010;

int n;
int a[N];
int b[N];int c[N];

const int V=10000010;
int lp[V];int prime[1000010];int tot_prime=0;
void seive(){
    int v=V-1;
    for(int i=2;i<=v;i++){
        if(!lp[i]){lp[i]=i;prime[++tot_prime]=i;}
        for(int j=1;j<=tot_prime&&i*prime[j]<=v;j++){
            lp[i*prime[j]]=prime[j];
        }
    }
}

signed main(){
    std::ios::sync_with_stdio(false);

    seive();
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];

        for(int i=1;i<=n;i++){
            b[i]=-1;c[i]=-1;
            int j=lp[a[i]];
            while(a[i]%j==0)a[i]/=j;
            
            if(a[i]>1){
                b[i]=j;c[i]=a[i];
            }
        }
        for(int i=1;i<=n;i++)cout<<b[i]<<" ";cout<<'\n';
        for(int i=1;i<=n;i++)cout<<c[i]<<" ";cout<<'\n';
    
}

E - Two Arrays

b[j]递增,所以如果a[i]被划分到b[j]这一段,a[i]的后缀最小值<=b[i]
切m-1刀,第j刀可以切在所有的a[i]==b[j+1]后

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long

const int p=998244353;
map<int,int> mp;
const int N=200010;
int n,m;int a[N];int b[N];

signed main(){
    std::ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    a[n+1]=0x3f3f3f3f;for(int i=n;i>=1;i--){a[i]=min(a[i],a[i+1]);mp[a[i]]++;}
    for(int i=1;i<=m;i++)cin>>b[i];

    if(a[1]!=b[1]){
        cout<<0;//如果头一个区间的最小值不能满足
        return 0;
    }
    int ans=1;
    for(int i=2;i<=m;i++){
        ans=(ans*mp[b[i]])%p;
    }
    cout<<ans;
}

F. Jog Around The Graph

容易发现\(O(n^2)\)dp,\(f[j][i]\)表示以i为结束点,走了长为j的路径的最大总权值
\(f[j][i]=max(f[j-1][i1]+w,f[j][i])\)\(m\)步为\(O(m*m)\)
q无穷大时一直反复走权值最大的边最优。\(q>=m\)\(m\)步之内必然能到达所有边,m步之后q无穷大时反复走这条边
但是不是权值最大的边任何时候都更优,它增长快,但是可能走到它的权值截距非常地小
\(f[j][v]=mx_v*(j-m)+f[m][v]\)q减去m后,\(mx_v\)为斜率,\(f[m][v]\)为直径。
考虑维护凸包,找出每条线作为最高的区间

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define int long long

const int P=1e9+7;
const int N=2010;
int n,m,q;
vector<pair<int,int>> G[N];
int m1,u1,v1;
int f[N][N];

struct EDGE{
    int u,v,w;
}e[N];int k[N];int b[N];

signed main(){
    std::ios::sync_with_stdio(false);
        cin>>n>>m>>q;
        for(int i=1;i<=m;i++){
            int u,v,w;cin>>u>>v>>w;G[u].push_back({v,w});G[v].push_back({u,w});
            e[i].u=u;e[i].v=v;e[i].w=w;
            if(m1<w){
                m1=w;u1=u;v1=v;
            }
        }

        //m=q;
        for(int j=0;j<=m;j++)for(int i=1;i<=n;i++)f[j][i]=-0x3f3f3f3f;
        f[0][1]=0;
        for(int j=1;j<=m;j++){
            for(int i=1;i<=n;i++){
                for(auto [i1,w]:G[i]){
                   f[j][i]=max(f[j][i],f[j-1][i1]+w);                 
                }
            }
        }
       

        
        int ans=0;int mx=0;
        for(int j=1;j<=m;j++){
            int tem=0;
            for(int i=1;i<=n;i++){
                tem=max(tem,f[j][i]);
            }
           // cout<<"get"<<j<<" "<<tem<<'\n';
            ans=(ans+tem)%P;
            if(j==m)mx=tem;
        }


        q-=m;
        for(int i=1;i<=m;i++){//斜率截距
            k[i]=e[i].w;b[i]=max(f[m][e[i].u],f[m][e[i].v]);
        }
        for(int i=1;i<=m;i++){
            int l=1;int r=q;//这一条线作为最高的区间
            for(int j=1;j<=m;j++){
                if(i!=j){
                    if(k[i]>k[j]){
                        l=max(l,(b[j]-b[i])/(k[i]-k[j])+1);
                    }else if(k[i]<k[j]){
                        r=min(r,(b[j]-b[i])/(k[i]-k[j]));
                    }else {//斜率相同
                        if(b[i]>b[j])continue;//i优
                        if(b[i]==b[j]&&i<=j)continue;//i优
                        l=q+1;//i永远在j下面
                    }
                }
            }
            if(l>r)continue;
            ans=(ans+((l+r)*(r-l+1)/2)%P*k[i]%P)%P;
            ans=(ans+b[i]*(r-l+1)%P)%P;
        }
        //ans=(ans+mx*(q-m)%P)%P;
        //ans=(ans+m1*((1+q-m)*(q-m)/2)%P%P)%P;
        cout<<ans<<'\n';
}
posted @ 2025-08-25 00:48  arin876  阅读(8)  评论(0)    收藏  举报