提高組聯賽訓練07.19

題目鏈接點這裏

王國道路(圖論)

*現在國王要建造道路,使得建造後的道路能夠使所有城市兩兩能夠相連通。

並且使得所有城市到首都一號城市的距離之和最小。

兩個城市間一條路徑的距離等於這條路徑上道路的最大值。兩個城市間的距離等於城市間的最短路徑。*

這道題坑啊
比賽結束前10min才解釋題意(雖然延時30min)
因爲我一開始打的是kruskal
所以腦補了一下記錄每個並查集的大小
在合併的時候更新答案
但是由於時間太緊
沒有打出來
下面是正解(最快)
每次取出隊列中的節點更新其他節點的答案

Spfa(883ms)

#include<cstdio>
#include<iostream>
#include<queue>
#define INF 2147483647
#define N 2010
using namespace std;
typedef long long LL;
LL ans;
queue<int>Q;
struct Edge{
    int p,q,o,n;
}b[N*N];
int n,m,p,q,o,u,v,s,t,num,h[N],d[N];
bool bo[N];
void ljb(int p,int q,int o){
    b[++num].n=h[p];
    h[p]=num;
    b[num].p=p;
    b[num].q=q;
    b[num].o=o;
}
void Spfa(){
    int x,y;
    while(!Q.empty()){
        x=Q.front(); Q.pop();
        bo[x]=0;
        for(int i=h[x];i!=0;i=b[i].n){
            y=b[i].q;
            if(max(d[x],b[i].o)<d[y]){
                d[y]=max(d[x],b[i].o);
                if(!bo[y]){
                    bo[y]=1;
                    Q.push(y);
                }
            }
//          printf("%d %d %d %d\n",x,y,d[x],d[y]);
        }
    }
}
int main(){
    freopen("data.txt","r",stdin);
    freopen("2.txt","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&p);
            if(i!=j)ljb(i,j,p);
        }
    }
    for(int i=1;i<=n;i++)if(i!=1)d[i]=INF;
    Q.push(1);
    bo[1]=1;
    Spfa();
//  for(int i=1;i<=n;i++)printf("%d ",d[i]);
//  printf("\n");
    for(int i=1;i<=n;i++)ans+=d[i];
    cout<<ans<<'\n';
}

我的蒟蒻kruskal

Kruskal(1008ms)

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 2010
typedef long long LL;
using namespace std;
int f[N],h[N],num,n,p,q,s[N];
LL ans;
struct edge{
    int u,v,w,n;
}e[N*N/2];
int fa(int x){
    if(f[x]!=x)f[x]=fa(f[x]);
    return f[x];
}
void ljb(int p,int q,int o){
    e[++num].n=h[p];
    h[p]=num;
    e[num].u=p;
    e[num].v=q;
    e[num].w=o;
}
bool cmp(edge p,edge q){
    return p.w<q.w;
}
void kruskal(){
    sort(e+1,e+num+1,cmp);
    int t=0;
    for(int i=1;i<=num;i++){
        p=e[i].u;
        q=e[i].v;
        if(fa(p)==fa(q))continue;
        if(f[p]==1)ans+=(LL)s[f[q]]*e[i].w;
        else if(f[q]==1)ans+=(LL)s[f[p]]*e[i].w;
        if(f[q]!=1){
            s[f[p]]+=s[f[q]];
            f[f[q]]=f[p];
        }
        else {
            s[f[q]]+=s[f[p]];
            f[f[p]]=f[q];
        }
        if(++t==n-1)break;
    }
    cout<<ans<<'\n';
}
int main(){
    freopen("data.txt","r",stdin);
    freopen("1.txt","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        f[i]=i;
        s[i]=1;
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            scanf("%d",&p);
            if(j>i)ljb(i,j,p);
        }
    }
    kruskal();
}

來自xyl的
他首先kruskal一遍
然後dfs找每個點到首都的距離
求和就行了

kruskal+dfs(1213ms)from xyl

#include <cstdio>
#include <algorithm>
#define maxn (2000+10)

using namespace std;

int f[maxn],vis[maxn],g,g2,ans,p,n,m,head[maxn],mp[maxn][maxn];

struct xx
{
    int u,v,next,q;
}b[maxn*maxn<<1],c[maxn<<1];

void add(int u,int v,int q)
{
    b[++g]=(xx){u,v,head[u],q};
    head[u]=g;
}

void add2(int u,int v,int q)
{
    c[++g2]=(xx){u,v,head[u],q};
    head[u]=g;
}

void dfs(int x,int tmp)
{
    ans+=tmp;
    vis[x]=1;
    for (int i=head[x];i;i=b[i].next)
    {
        int v=b[i].v;
        if (vis[v]) continue;
        dfs(v,max(tmp,b[i].q));
    }
    return ;
}

int _find(int x)
{
    return x==f[x]?x:f[x]=_find(f[x]);
}

int cmp(xx A,xx B)
{
    return A.q<B.q;
}

int main()
{

    scanf("%d",&n);
    for (int i=1;i<=n;++i)
      for (int j=1;j<=n;++j)
        scanf("%d",&mp[i][j]);
    for (int i=1;i<=n;++i)
      for (int j=i+1;j<=n;++j)
        add(i,j,mp[i][j]),add(j,i,mp[i][j]);
    sort(b+1,b+1+g,cmp);
    for (int i=1;i<=n;++i) head[i]=0,f[i]=i;
    for (int i=1;i<=g;++i)
    {
        if (p==n-1) break;
        int t1=_find(b[i].u);
        int t2=_find(b[i].v);
        if (t1!=t2) add(b[i].u,b[i].v,b[i].q),add(b[i].v,b[i].u,b[i].q),f[t1]=t2,++p;
    }
    vis[1]=1;
    for (int i=head[1];i;i=b[i].next)
      dfs(b[i].v,b[i].q);
    printf("%d",ans);
    return 0;
}

數位變換

首先k進制下N=xxxxxxx(末尾前的幾位)ddddddd(末尾的多少個d)
移項:N-d=xxxxxxxddddddd0
N-d=0(mod k)
所以k是N-d的因子
枚舉就行了

#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long LL;
int p,ans,m;
LL n,num;
int Solve(LL x,LL k,int m){
    if(k==1)return 0;
//  cout<<x<<' '<<k<<'\n';
    int cnt=0;
    while(x!=0){
        if(x%k==m)cnt++;
        else return cnt;
        x/=k;
    }
    return cnt;
}
int main(){
    while(scanf("%lld%d",&n,&m)==2){
        ans=0;
        num=2;
//      for(LL i=max(2,m+1);i<=n+1;i++){
        for(LL i=1;i<=sqrt(n-m);i++){
            if((n-m)%i!=0)continue;
            p=Solve(n,i,m);
//          cout<<n<<' '<<i<<' '<<p<<'\n';
            if(ans<p||(ans==p&&num>i)){
                ans=p;
                num=i;
            }
            p=Solve(n,(n-m)/i,m);
//          cout<<n<<' '<<(n-m)/i<<' '<<p<<'\n';
            if(ans<p||(ans==p&&num>(n-m)/i)){
                ans=p;
                num=(n-m)/i;
            }
        }
        cout<<num<<' '<<ans<<'\n';
    }
}

股票傳說

滿分暴力加優化

#include<cstdio>
#include<iostream>
#define N 100010
using namespace std;
typedef long long LL;
LL d[N];
int a[N],n,m,f;
int main(){
    freopen("data.txt","r",stdin);
    scanf("%d%d%d",&n,&m,&f);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    d[0]=m;
    for(int i=1;i<=n;i++){
        d[i]=d[i-1];
        for(int j=1;j<i;j++)d[i]=max(d[i],d[j]+(d[j]-f)/a[j]*(a[i]-a[j])-2*f);
    }
    cout<<d[n]<<'\n';
}

正解

#include<cstdio>
#include<iostream>
#define N 100010
using namespace std;
typedef long long LL;
LL d[N],a[N],b[N];
int n,m,f,p;
int main(){
    scanf("%d%d%d",&n,&m,&f);
    d[0]=m;
    for(int i=1;i<=n;i++){
        scanf("%d",&p);
        d[i]=max(d[i-1],a[i-1]*p-f+b[i-1]);
        if((d[i-1]-f)/p>a[i-1]||((d[i-1]-f)/p==a[i-1]&&(d[i-1]-f)%p>b[i-1])){
            a[i]=(d[i-1]-f)/p;
            b[i]=(d[i-1]-f)%p;
        }
        else {
            a[i]=a[i-1];
            b[i]=b[i-1];
        }
    }
    cout<<d[n];
}

完美正解:
斜率優化
然後cdq分治(或splay)維護一個凸包

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章