AcWing 第11場周賽題解

計算abc

首先 \(0<=a<=b<=c\)
會隨機給出
\(a+b,a+c,b+c,a+b+c\)的值node

由於\(a,b,c\)都爲正整數,因此\(a+b+c\)必定爲最大值
而後用\(a+b+c\)逐個減去便可(注意\(a,b,c\)大小ios

  • code
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int x[5];
int main(){
	for(int i=1;i<=4;++i) cin>>x[i];
	sort(x+1,x+5);
	for(int i=3;i>=1;--i) cout<<x[4]-x[i]<<" ";
	return 0;
}

湊平方

根據題意模擬,不難想到暴力枚舉,枚舉出每個由原數刪了後的數
再看數據範圍,數的長度最多十位,因此每一個數最多枚舉2^10次,每次枚舉最多10次,\(t<=10\)組數據
n爲數的長度
因此時間複雜度\(O(2^n*n*t)\)spa

  • 具體實現
    (dfs,bfs均可以)
    這裏有一種巧妙,易實現的方法

利用二進制
舉個例子
原數\(2081\)
$(1010)_2 $ 1就表明不刪相應位置數,0表明刪了相應位置的數
按照上述規則,刪了後的數爲 28
\((0111)_2\) 刪了後的數字爲 081 ,但這裏你會發現有前導0,但其實具體實現的時候不會有這個問題,由於咱們是一位一位的轉化成整型,巧妙的避免了前導0的問題
既然是找最少次刪除操做
那枚舉順序\(0-2^n\)code

  • code
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>

using namespace std;
string s;
int t;
int stlen(int x){//求x的位數
    int ans=0;
    for(;x;++ans) x/=10;return ans;
}
int main(){
    cin>>t;
    while(t--){
        cin>>s;
        int len=s.length();
        int ans=100;
        for(int i=0;i<(1<<len);++i){
            int x=0;
            for(int j=0;j<len;++j)
                if(i>>j & 1)
                    x=x*10+s[j]-'0';
            int sq=sqrt(x);
            if(x && sq*sq==x) ans=min(ans,len-stlen(x));
        }
        if(ans!=100) cout<<ans<<endl;
        else cout<<"-1"<<endl;
    }
}

最大化最短路

突破口 :必須選出兩個特殊點
那麼考慮三種狀況
設兩個特殊點分別爲\(x,y\)排序

  • 選了\(x,y\)但不通過任意\(x,y\)ci

  • 通過兩個\(x,y\)最短路徑是從\(1——>n\)get

  • 通過兩個\(x,y\)最短路徑是從\(n——>1\)string

\(dis1[],dis2[]\)分別爲1到各個點的最短距離,n到各個點的最短距離
三種狀況分別能得出的答案即爲
1.\(dis1[n]\) (不通過任何點即爲最短路
2.\(dis1[x]+1+dis2[y]\) (1——>x+x——>y+y——n
3.\(dis2[x]+1+dis1[y]\) (n——>x+x——>y+y——1it

求出後兩種狀況的最大值以後
在三者狀況種取最小值(爲何不取較大兩個值,由於較大兩個雖然構成最短路,但在三種狀況一塊兒討論的時候,並不較大的兩個值並不構成最短路
也就是說,添加一條邊以後頗有可能最短距離會減少)io

第一狀況跑一下最短路就可
第二種和第三種狀況,首先要預處理
\(dis1[]和dis2[]\),跑一遍最短路便可

最終求的是1到n最短距離儘量大

因此如今的目標就是求出2,3狀況的最大值,取其中得最小值(
若是暴力求話直接GG
假設\((i,j)\)爲一對且\(i!=j\),並且i,j∈特殊點
任取一對,則二三狀況獲得的答案
\(max(min(dis1[i]+1+dis2[j],dis1[j]+dis[i]+1))\)

當dis1[i]+1+dis2[j]<=dis1[j]+dis[i]+1時
即dis1[i]-dis2[i]<=dis[j]-dis2[j];

將數對根據差值排序
此時
當數對後一個爲x時
取max(dis1[1~x-1])+dis2[x])
x從1~k

取出的最大值,最後與dis1[n]取最小值便可

  • code
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<iostream>

using namespace std;
int n,m,k;const int maxn=2e5+10;
int head[maxn*2];
int p[maxn];
int cnt=0;
int dis1[maxn],dis2[maxn];
struct node{
    int v,next;
}e[maxn*2];
void add(int u,int v){
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}
bool cmp(int a,int b){
    return dis1[a]-dis2[a]<dis1[b]-dis2[b];
}
void dj(int st,int dis[]){
    bool vl[maxn];
    memset(vl,0,sizeof(vl));
    memset(dis,0x3f3f3f3f,maxn*4);
    dis[st]=0;
    priority_queue<pair<int,int>  >q;
    q.push(make_pair(-dis[1],st));
    while(!q.empty()){
        int u=q.top().second;q.pop();
        if(vl[u]) continue;
        vl[u]=1;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].v;
            if(dis[v]>dis[u]+1){
                dis[v]=dis[u]+1;
                q.push(make_pair(-dis[v],v));
            }
        }
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);memset(head,0,sizeof(head));
    for(int i=1;i<=k;++i) scanf("%d",&p[i]);
    for(int i=1;i<=m;++i){
        int u,v;scanf("%d%d",&u,&v);
        add(u,v);add(v,u);
    }
    dj(1,dis1);
    dj(n,dis2);
    sort(p+1,p+1+k,cmp);
    int res=0,x=dis1[p[1]];
    for(int i=2;i<=k;++i){
        int t=p[i];
        res=max(res,dis2[t]+x+1);
        x=max(x,dis1[t]);
    }
    printf("%d",min(res,dis1[n]));return 0;
}
相關文章
相關標籤/搜索