10.2司機出的考試太太太太毒瘤了...用組裏某嚶嚶怪的話說:ios
「看起來人畜無害,出題比誰都變態。」算法
因爲博主太過蒟(懶)蒻(惰),因此題解就沒有啦!數組
今天貓的題仍是很友善的...
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; }