当前位置: 代码迷 >> 综合 >> 【CCPC-Wannafly Winter Camp Day1 (Div2, onsite) 】
  详细解决方案

【CCPC-Wannafly Winter Camp Day1 (Div2, onsite) 】

热度:28   发布时间:2023-12-29 02:10:22.0

前言


过年在家颓废很久之后终于开始嫌弃自己,开始认真了。
开始开专题并且补完CAMP的题解。
这是第一天的camp题解,赛中只做出BCFJ四个题。
赛后补完:ABCEFIJ


题解


A.机器人

题意

wls管理的仓库分为ABABAB两个区,这两个区坐落在两条平行的直线上,每个区有nnn个站点,标号分别为1...n1...n1...nagvagvagv从站点aaa到同仓库的站点bbb需要花费abs(a?b)abs(a-b)abs(a?b)的时间。存在mmm个特殊的站点,假如第iii个站点是特殊的,那么agvagvagv可以花费kkk的时间从一个区的iii号站点开到另一个区的iii号站点,agvagvagv只能通过这些特殊站点实现区与区之间的转换。111号,nnn号两个站点都是特殊的站点。
由于特殊的原因,在同一个区域内,agvagvagv只能在特殊站点掉头,否则他们只能沿着同一个方向运行。现在agvagvagv正在AAA区的站点sss上,他需要经过rrr个给定的站点并回到原处,请问最少需要多少时间?你可以指定agvagvagv的初始方向。

做法

通过分类讨论,我们可以知道最终情况只有以下四种。
每种情况分别通过二分计算即可。
第一种情况(要经过的点都和起点同侧,而且均在起点的一侧):第一种情况(要经过的点都和起点同侧,而且均在起点的一侧):():
在这里插入图片描述
这种情况只需要找到最接近最右侧点而且在最右侧点右侧的关键点即可。
第二种情况(要经过的点都和起点同侧,并且遍布起点的两侧):第二种情况(要经过的点都和起点同侧,并且遍布起点的两侧):():
在这里插入图片描述
这种情况只需要找到能让两侧转变方向的最优关键点即可,对于这个的查询可以直接用lower_bound查询。
第三种情况(要经过的点在AB两侧都有,并且都在起点的同一侧):第三种情况(要经过的点在AB两侧都有,并且都在起点的同一侧):(AB):
在这里插入图片描述
当所有点都在同一侧,而且需要的关键点也在同一侧时,可以直接这样走。
第四种情况(要经过的点在AB两侧都有,并且遍布在起点的两侧):第四种情况(要经过的点在AB两侧都有,并且遍布在起点的两侧):(AB):
在这里插入图片描述

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;const int maxn = 1e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endlvector<int>vec[2];//存放两侧要到达的点
vector<int>x;//存放关键点int main()
{
    int n,r,m,k,s,u,v;scanf("%d%d%d%d%d",&n,&r,&m,&k,&s);for(int i=1;i<=r;i++){
    scanf("%d%d",&u,&v);vec[v].push_back(u);}for(int i=1;i<=m;i++){
    scanf("%d",&u);x.pb(u);}x.pb(1);x.pb(n);int flag1=0,flag2=0;sort(x.begin(),x.end());int minn=n,maxx=1;for(int i=0;i<vec[0].size();i++){
    if(vec[0][i]>s) flag1=1;if(vec[0][i]<s) flag2=1;maxx=max(maxx,*(lower_bound(x.begin(),x.end(),vec[0][i])));//找到第一个在该点右侧的关键点minn=min(minn,*(upper_bound(x.begin(),x.end(),vec[0][i])-1));//找到第一个在该点左侧的关键点}if(vec[1].size()==0)//所有点都在一侧{
    if(flag1==0&&flag2==0) printf("0\n");//只有起点一个点else if(flag1==0) printf("%d\n",2*(s-minn));//只有起点左侧有点else if(flag2==0) printf("%d\n",2*(maxx-s));//只有起点右侧有点else printf("%d\n",2*(maxx-minn));//起点两侧都有点}else{
    int minnb=n,maxxb=1;for(int i=0;i<vec[1].size();i++){
    maxxb=max(maxxb,*(lower_bound(x.begin(),x.end(),vec[1][i])));//找到第一个在该点右侧的关键点minnb=min(minnb,*(upper_bound(x.begin(),x.end(),vec[1][i])-1));//找到第一个在该点左侧的关键点}maxx=max(maxx,maxxb);minn=min(minn,minnb);if(flag1==0&&maxxb<=s) printf("%d\n",(s-minn+k)*2);//只有起点左侧有点else if(flag2==0&&minnb>=s) printf("%d\n",(maxx-s+k)*2);//只有起点右侧有点else printf("%d\n",2*(maxx-minn+k));//起点两侧都有点}return 0;
}

B.吃豆豆

题意

wlswlswls有一个nnnmmm列的棋盘,对于第iii行第jjj列的格子,每过T[i][j]T[i][j]T[i][j]秒会在上面出现一个糖果,第一次糖果出现在第T[i][j]T[i][j]T[i][j]秒,糖果仅会在出现的那一秒存在,下一秒就会消失。假如wlswlswlskkk秒在第iii行第jjj列的格子上,满足T[i][j]∣kT[i][j] | kT[i][j]k,则wlswlswls会得到一个糖果。
假如当前wlswlswls在第iii行第jjj列的格子上,那么下一秒他可以选择往上下左右走一格或停在原地。
现在请问wlswlswls从指定的SSS出发到达指定的TTT,并且在路上得到至少CCC个糖果最少需要多少时间?
wlswlswlsSSS的初始时间为第000秒。
1≤n,m,T[i][j]≤101≤n,m,T[i][j]≤101n,m,T[i][j]10
1≤C≤10181 \leq C \leq 10181C1018
做法

可以看到这道题n,m,cn,m,cn,m,c都很小。
但是这道题的关键在于换一个方向思考问题,我们直接用dp[i][j][k]dp[i][j][k]dp[i][j][k]表示到达点(i,j)(i,j)(i,j)得到k个糖果的最短时间的话,是不能dpdpdp的,因为上一个状态不确定,无法dpdpdp。但是我们可以发现最后的答案一定不会超过C?10C*10C?10,因为我们可以站在一个位置不动,用这些时间就能达到目的,所以我们可用dp[i][j][k]dp[i][j][k]dp[i][j][k]表示到达点(i,j)(i,j)(i,j)经过时间kkk能达到的最大糖果数,这就很容易dpdpdp了。只要从k?1k-1k?1的能到达本点的状态去转移即可。最后找到能到在终点能得到CCC个糖果的最短时间即可。

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
int dp[15][15][12005];
int T[15][15];
int dis[5][2]={
    -1,0,1,0,0,-1,0,1,0,0};
int main()
{
    int n,m,c;memset(dp,-1,sizeof(dp));scanf("%d%d%d",&n,&m,&c);for(int i=1;i<=n;i++){
    for(int j=1;j<=m;j++){
    scanf("%d",&T[i][j]);}}int ans;int stx,sty,enx,eny;scanf("%d%d%d%d",&stx,&sty,&enx,&eny);dp[stx][sty][0]=0;for(int i=1;i<=10999;i++){
    for(int j=1;j<=n;j++){
    for(int k=1;k<=m;k++){
    for(int l=0;l<5;l++){
    if(i%T[j][k]==0&&dp[j+dis[l][0]][k+dis[l][1]][i-1]!=-1){
    dp[j][k][i]=max(dp[j][k][i],dp[j+dis[l][0]][k+dis[l][1]][i-1]+1);}else if(dp[j+dis[l][0]][k+dis[l][1]][i-1]!=-1){
    dp[j][k][i]=max(dp[j][k][i],dp[j+dis[l][0]][k+dis[l][1]][i-1]);}}}}if(dp[enx][eny][i]>=c){
    ans=i;break;}}printf("%d\n",ans);return 0;
}

C.拆拆拆数

题意

读入A和BA和BAB,wlswlswls想请你把A拆成a1,a2,a3...,ana_1,a_2,a_3...,a_na1?,a2?,a3?...,an?, 把B拆成b1,b2.b3...,bnb_1,b_2.b_3...,b_nb1?,b2?.b3?...,bn?, 满足
1.对于所有的i(1≤i≤n),ai,bi≥2且gcd(ai,bi)=1i(1 \leq i \leq n),a_i,b_i \ge 2且gcd(a_i,b_i) = 1i(1in),ai?,bi?2gcd(ai?,bi?)=1
2.Σi=1nai=A,Σi=1nbi=B\varSigma _{i=1}^{n}a_i=A,\varSigma _{i=1}^{n}b_i=BΣi=1n?ai?=A,Σi=1n?bi?=B
如果有多组满足条件的aaabbb,请输出nnn最小的任意一组即可。
如果无解,请输出?1?1?1
5≤A,B≤10185 \leq A,B \leq 10^{18}5A,B1018
做法

首先如果两个数本来就是互质的,只分成一组即可
其余的情况我们猜测分为两组即可
首先我们找到第一个不是AAA的因子也不是BBB的因子的质数PPP
然后这样拆分A,BA,BA,B
A?PPA-P \ \ \ \ PA?P    P
PB?PP \ \ \ \ \ \ \ \ \ \ \ B-PP           B?P
因为AAA不是PPP的倍数,所以A?PA-PA?P不是PPP的倍数,所以gcd(A?P,P)=1gcd(A-P,P)=1gcd(A?P,P)=1
因为BBB不是PPP的倍数,所以B?PB-PB?P不是PPP的倍数,所以gcd(P,B?P)=1gcd(P,B-P)=1gcd(P,B?P)=1
因为前15个质数相乘就已经大于101810^{18}1018 ,所以枚举到第15个质数即可。
代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<queue>
#include<map>
#include<bitset>
#include<stack>
#include<set>
#include<vector>
#include <time.h>
#include<string.h>
using namespace std;typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <ll, int> pli;
typedef pair <db, db> pdd;const int maxn = 1e5+5;
const int Mod=1000000007;
const int INF = 0x3f3f3f3f;
const ll LL_INF = 0x3f3f3f3f3f3f3f3f;
const double e=exp(1);
const db PI = acos(-1);
const db ERR = 1e-10;#define Se second
#define Fi first
#define pb push_back
#define dbg(x) cout<<#x<<" = "<< (x)<< endl
#define dbg2(x1,x2) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<endl
#define dbg3(x1,x2,x3) cout<<#x1<<" = "<<x1<<" "<<#x2<<" = "<<x2<<" "<<#x3<<" = "<<x3<<endl
ll gcd_(ll a, ll b)
{
    return b ==0? a : gcd_(b, a % b);
}
int prime[maxn];
int flag[maxn+5];//素数flag->0
int mp[maxn];
int tot;
void make_prime()
{
    for(int i=2;i<=300;i++)if(!flag[i]){
    prime[++tot]=i;mp[i]=tot;for(int j=i+i;j<=maxn;j+=i)flag[j]=1;}
}
int main()
{
    make_prime();int t;scanf("%d",&t);while(t--){
    ll a,b;scanf("%lld%lld",&a,&b);if(gcd_(a,b)==1){
    printf("1\n%lld %lld\n",a,b);}else if(a%2==1&&b%2==1){
    printf("2\n");printf("%lld %lld\n",2,b-2);printf("%lld %lld\n",a-2,2);}else{
    ll n=a;ll m=b;ll tt;for(int i=1;i<=15;i++){
    if((a%prime[i]!=0)&&(b%prime[i]!=0)){
    tt=prime[i];break;}}if(tt>=n&&tt>=m){
    printf("-1\n");}else{
    if(tt>=n){
    ll x1,x2;x2=m-tt;ll tmpx=x2;ll tmptt;for(int i=1;i<=15;i++){
    if(tmpx%prime[i]!=0){
    tmptt=prime[i];break;}}x1=tmptt;if(n-x1<=1) printf("-1\n");else{
    printf("2\n");printf("%lld %lld\n",x1,x2);printf("%lld %lld\n",n-x1,m-x2);}}else if(tt>=m){
    swap(n,m);ll x1,x2;x2=m-tt;ll tmpx=x2;ll tmptt;for(int i=1;i<=15;i++){
    if(tmpx%prime[i]!=0){
    tmptt=prime[i];break;}}x1=tmptt;if(n-x1<=1) printf("-1\n");else{
    printf("2\n");printf("%lld %lld\n",x2,x1);printf("%lld %lld\n",m-x2,n-x1);}}else{
    printf("2\n");printf("%lld %lld\n",tt,m-tt);printf("%lld %lld\n",n-tt,tt);}}}}return 0;
}

题意

做法

代码



题意

做法

代码



题意

做法

代码



题意

做法

代码


  相关解决方案