博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2018.10.4模拟考试
阅读量:5880 次
发布时间:2019-06-19

本文共 6624 字,大约阅读时间需要 22 分钟。

10.2司机出的考试太太太太毒瘤了...用组里某嘤嘤怪的话说:

看起来人畜无害,出题比谁都变态。

由于博主太过蒟(懒)蒻(惰),所以题解就没有啦!

 

今天猫的题还是很友善的...

T1 题上说每次必须融合一个马猴值为1的龙珠,因此可以设A=a/b,B=1。

   那么第一种融合即为a/b+1=(a+b)/b

       第二种融合即为1/(b/a+1)=a/(a+b)

   发现两种融合即为分子/(分子+分母)或(分子+分母)/分母

   因此题目可以简化为:对于二元组(a,b),每次操作可以使二元组中的一个数加上另一个数,求到达最

   终状态(c,d)的最少操作数。

   发现整个过程的逆过程类似于求gcd。

#include
//STL通用算法#include
//STL位集容器#include
#include
#include
#include
#include
#include
#include
#include
//STL双端队列容器#include
//STL线性列表容器#include
//STL映射容器#include
#include
//STL队列容器#include
//STL集合容器#include
//STL堆栈容器#include
//STL通用模板类#include
//STL动态数组容器#define INF 0x3f3f3f3f#define ll long longusing 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

 


 

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
//STL通用算法#include
//STL位集容器#include
#include
#include
#include
#include
#include
#include
#include
//STL双端队列容器#include
//STL线性列表容器#include
//STL映射容器#include
#include
//STL队列容器#include
//STL集合容器#include
//STL堆栈容器#include
//STL通用模板类#include
//STL动态数组容器#define INF 0x3f3f3f3f3f3f3f3f#define ll long long#define MOD 1000000007using namespace std;typedef vector
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
<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 
#include
#include
#include
#include
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
struct data { int v; bool operator < (const data& a) const { return dis[v] > dis[a.v]; }} ;priority_queue
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;}

 

转载于:https://www.cnblogs.com/water-radish/p/9742360.html

你可能感兴趣的文章
centos7.2安装john-1.8.0
查看>>
VMware Ubuntu NAT上网方式配置
查看>>
RHEL与Fedora版本关系
查看>>
linux运维实战练习-2015年8月30日课程作业
查看>>
导入excel
查看>>
《跟老男孩学Linux运维之shell编程实战》-第二章 shell变量的核心基础
查看>>
puppet客户端认证
查看>>
我的友情链接
查看>>
Lombardi WebAPI 详解
查看>>
NET 2.0 - WinForm Control - DataGridView 编程36计(一)
查看>>
从语言层次的角度看为什么要精通C语言
查看>>
oracle登陆受限问题
查看>>
docker集群(一)--简单应用portainer
查看>>
linux线程锁使用实例
查看>>
HTML第一讲
查看>>
kafka入门
查看>>
Redis 占用Windows系统盘空间23G
查看>>
linux 内存分配
查看>>
续费Enom域名的三种办法
查看>>
backtop返回页面顶部jquery代码
查看>>