2018.10.4模擬考試

10.2司機出的考試太太太太毒瘤了...用組裏某嚶嚶怪的話說:ios

看起來人畜無害,出題比誰都變態。算法

因爲博主太過蒟(懶)蒻(惰),因此題解就沒有啦!數組

願意瞄一眼司機的毒瘤題的各位巨佬請戳我!ide

 

今天貓的題仍是很友善的...
spa

看題請戳我!code

T1 題上說每次必須融合一個馬猴值爲1的龍珠,所以能夠設A=a/b,B=1。blog

   那麼第一種融合即爲a/b+1=(a+b)/b隊列

       第二種融合即爲1/(b/a+1)=a/(a+b)get

   發現兩種融合即爲分子/(分子+分母)或(分子+分母)/分母string

   所以題目能夠簡化爲:對於二元組(a,b),每次操做可使二元組中的一個數加上另外一個數,求到達最

   終狀態(c,d)的最少操做數。

   發現整個過程的逆過程相似於求gcd。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL雙端隊列容器
#include<list>//STL線性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL隊列容器
#include<set>//STL集合容器
#include<stack>//STL堆棧容器
#include<utility>//STL通用模板類
#include<vector>//STL動態數組容器
#define INF 0x3f3f3f3f
#define ll long long
using namespace std;
ll ans,a,b,k;
int main()
{
    freopen("dragon.in","r",stdin);
    freopen("dragon.out","w",stdout);
    scanf("%lld%lld%lld",&a,&b,&k);
    if(!a||!b) {printf("-1\n");return 0;}
    if(a<b) swap(a,b);
    while(b) {ans+=a/b;a%=b;swap(a,b);}
    printf("%lld\n",ans*k);
    return 0;
}

 


 

T2 一道純思路題。

   把三枚棋子之間的兩段距離看作此狀態的兩個參數。

   因爲在某一狀態下,其能轉移到的狀態最少2種,最多3種:

   1.a<--->b<------->c 在此狀態下,b能夠向左或向右跳,a能夠向右跳;

   2.a<------->b<--->c 在此狀態下,b能夠向左或向右跳,c能夠向左跳;

   3.a<----->b<----->c 在此狀態下,b能夠向左或向右跳。

   發現不管是哪一種狀態,中間的旗子都能向兩邊跳,而兩側的棋子卻不必定能向中間跳。

   若把每一個狀態都抽象成一個點,那麼以上規律可總結爲:

   在一棵樹上,每一個節點都有2個兒子,卻不必定有父親。(根節點)

   所以此題轉化成了樹上求兩點間路徑+統計多餘步數分配方案數。

   因爲最大步數僅有100步,所以能夠直接從起始狀態與終止狀態分別向上暴跳k步,找到最深的公共節點

   即爲LCA。(若無符合條件的節點則無解)

   那麼如何統計多餘步數的分配方案數呢?

   發現不管如何消耗步數,其方式無非2種:向路徑外走或走迴路徑。可用dp實現。

#include<algorithm>//STL通用算法
#include<bitset>//STL位集容器
#include<cctype>
#include<cmath>
#include<complex>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<deque>//STL雙端隊列容器
#include<list>//STL線性列表容器
#include<map>//STL映射容器
#include<iostream>
#include<queue>//STL隊列容器
#include<set>//STL集合容器
#include<stack>//STL堆棧容器
#include<utility>//STL通用模板類
#include<vector>//STL動態數組容器
#define INF 0x3f3f3f3f3f3f3f3f
#define ll long long
#define MOD 1000000007
using namespace std;
typedef vector<ll> vec;
ll a,b,c,d,e,f,n,root,dis1=INF,dis2=INF,disrt=-1,disup;
vec fst[101],lst[101];
ll dp[101][201][201];
vec go_up(const vec &x)
{
    if(x[1]-x[0]==x[2]-x[1]) return x;
    vec tmp(3);
    if(x[1]-x[0]>x[2]-x[1])
        tmp[0]=x[0],tmp[1]=x[1]*2-x[2],tmp[2]=x[1];
    else tmp[0]=x[1],tmp[1]=x[1]*2-x[0],tmp[2]=x[2];
    return tmp;
}
ll dfs(ll len,ll l,ll r)
{
    if(l<root||r<0||len<0) return 0;
    ll &tmp=dp[len][l][r];
    if(tmp>=0) return tmp;tmp=0;
    if(l>r)                                                    //在起點到終點的路徑上 
        (tmp+=dfs(len-1,l-1,r))%=MOD,                          //向根走 
        (tmp+=dfs(len-1,l+1,r)*2%MOD)%=MOD;                    //向終點走 
    if(l==r)                                                   //不在起點到終點的路徑上 
        (tmp+=dfs(len-1,l-1,r-1))%=MOD,                        //往回走 
        (tmp+=dfs(len-1,l+1,min(disup-dis1+dis2,r+1)))%=MOD,   //往終點走 
        (tmp+=dfs(len-1,l+1,r))%=MOD;                          //往起點走 
    return tmp;
}
int main()
{
    freopen("rabbit.in","r",stdin);
    freopen("rabbit.out","w",stdout);
    scanf("%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f,&n);
    fst[0].push_back(a),fst[0].push_back(b),fst[0].push_back(c);
    lst[0].push_back(d),lst[0].push_back(e),lst[0].push_back(f);
    sort(fst[0].begin(),fst[0].end());
    sort(lst[0].begin(),lst[0].end());
    for(ll i=1;i<=n;i++) fst[i]=go_up(fst[i-1]),lst[i]=go_up(lst[i-1]);
    for(ll i=0;i<=n;i++)
    {
        ll flg=0,j=0;
        for(j=0;j<=n;j++)
            if(fst[i]==lst[j]) {flg=1;break;}
        if(flg) {dis1=i,dis2=j;break;}
    }
    if(dis1+dis2>n) {printf("0\n");return 0;}
    vec tort=fst[dis1];
    for(ll i=dis1+1;i<=n;i++)
    {
        vec tmp=go_up(tort);
        if(tmp==tort)
        {disrt=i-1-dis1;break;}
        tort=tmp;
    }
    if((dis1+dis2)%2!=n%2) {printf("0\n");return 0;}
    //若此條件不知足,則在消耗多餘步數時沒法回到原點 
    disup=(n-dis1-dis2)/2+dis1;
    if(disrt>=0) root=disup-dis1-disrt;
    memset(dp,-1,sizeof(dp));
    dp[0][disup-dis1+dis2][disup-dis1+dis2]=1;
    printf("%lld\n",dfs(n,disup,disup-dis1));
    return 0;
}

 


 

T3 又一道思路題...

   然而前15個數據點分5部分分別暴力可拿60分2333

   標算是分治最短路。

   發現每一個城市最多5個派送點,一次性橫跨城市最多3個,這就是說,在n個派送點中去除最多15個連

   續的派送點會使左右兩側的派送點不連通。換句話說,左右兩邊的派送點想要互相到達,必須通過中

   間這15個派送點。能夠依據這個性質進行分治。

   對於k個城市內的每個配送點進行一次分治,查出每一個詢問的l與r到分治點的最短路,取最優便可。

   因爲博主已經被第二題虐的死去活來,故僅把std放上來供大佬們參考。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;

const int MaxN = 50010;
const int MaxM = 200010;

int n, m, k, p, q;
int belong[MaxM * 10], place_num;
int sum[MaxM], c[MaxM];
long long dis[MaxM * 10];
long long ans[MaxM];
int vis[MaxM * 10];
struct edge {
    int to, w;
    edge *next;
} *last[MaxM], e[MaxM << 1], *edge_cnt = e;

struct query {
    int s, t, i;
} ask[MaxM], t[MaxM];

void add_edge(int u, int v, int w) {
    *++ edge_cnt = (edge) {v, w, last[u]}, last[u] = edge_cnt;
}

#include <queue>
struct data {
    int v;

    bool operator < (const data& a) const {
        return dis[v] > dis[a.v];
    }
} ;
priority_queue <data > que;

void spfa(int l, int r, int s) {
    for (int i = sum[l - 1] + 1; i <= sum[r]; ++ i) dis[i] = 1ll << 60;
    for (vis[s] = 1, dis[s] = 0, que.push((data) {
    s
}); que.size(); vis[que.top().v] = 0, que.pop()) {
        for (edge *iter = last[que.top().v]; iter; iter = iter -> next) {
            if (l <= belong[iter -> to] && belong[iter -> to] <= r && (dis[iter -> to] > dis[que.top().v] + iter -> w ? dis[iter -> to] = dis[que.top().v] + iter -> w, 1 : 0)) {
                if (!vis[iter -> to]) {
                    vis[iter -> to] = 1;
                    que.push((data) {
                        iter -> to
                    });
                }
            }
        }
    }
}

void divide(int l, int r, int ql, int qr) {
    if (ql > qr) return ;
    if (r - l + 1 <= k + 5) {
        for (int i = ql; i <= qr; ++ i) {
            spfa(l, r, ask[i].s);
            ans[ask[i].i] > dis[ask[i].t] ? ans[ask[i].i] = dis[ask[i].t] : 0;
        }
        return ;
    }
    int ll = r + l - k >> 1, rr = ll + k + 1;
    int qll = ql, q1, q2;
    for (int i = ql; i <= qr; ++ i) t[i] = ask[i];
    for (int i = ql; i <= qr; ++ i) {
        if (belong[t[i].s] <= ll && belong[t[i].t] <= ll) ask[qll ++] = t[i];
    }
    q1 = qll - 1;
    for (int i = ql; i <= qr; ++ i) {
        if (belong[t[i].s] >= rr && belong[t[i].t] >= rr) ask[qll ++] = t[i];
    }
    q2 = qll - 1;
    for (int i = ql; i <= qr; ++ i) {
        if (!(belong[t[i].s] <= ll && belong[t[i].t] <= ll || belong[t[i].s] >= rr && belong[t[i].t] >= rr)) ask[qll ++] = t[i];
    }
    for (int i = sum[ll] + 1; i <= sum[rr - 1]; ++ i) {
        spfa(l, r, i);
        for (int j = ql; j <= qr; ++ j) {
            ans[ask[j].i] > dis[ask[j].s] + dis[ask[j].t] ? ans[ask[j].i] = dis[ask[j].s] + dis[ask[j].t] : 0;
        }
    }
    divide(l, ll, ql, q1);
    divide(rr, r, q1 + 1, q2);
}

int main() {
//    freopen("transport.in", "r", stdin);
//    freopen("transport.out", "w", stdout);
    scanf("%d%d%d%d%d", &n, &m, &k, &p, &q);
    for (int i = 1; i <= n; ++ i) {
        scanf("%d", c + i);
        for (int j = 1; j <= c[i]; ++ j) belong[++ place_num] = i;
        sum[i] = sum[i - 1] + c[i];
    }
    memset(ans, 63, sizeof ans);
    for (int i = 1; i <= m; ++ i) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        add_edge(u, v, w);
        add_edge(v, u, w);
    }
    for (int i = 1; i <= q; ++ i) {
        int s, t;
        scanf("%d%d", &s, &t);
        ask[i] = (query) {
            s, t, i
        };
    }
    divide(1, n, 1, q);
    for (int i = 1; i <= q; ++ i) {
        if (ans[i] > 1000000000) puts("-1");
        else printf("%lld\n", ans[i]);
    }
    return 0;
}
相關文章
相關標籤/搜索