前言
过年在家颓废很久之后终于开始嫌弃自己,开始认真了。
开始开专题并且补完CAMP的题解。
这是第一天的camp题解,赛中只做出BCFJ四个题。
赛后补完:ABCEFIJ
题解
A.机器人
题意
wls管理的仓库分为两个区,这两个区坐落在两条平行的直线上,每个区有个站点,标号分别为,从站点到同仓库的站点需要花费的时间。存在个特殊的站点,假如第个站点是特殊的,那么可以花费的时间从一个区的号站点开到另一个区的号站点,只能通过这些特殊站点实现区与区之间的转换。号,号两个站点都是特殊的站点。
由于特殊的原因,在同一个区域内,只能在特殊站点掉头,否则他们只能沿着同一个方向运行。现在正在区的站点上,他需要经过个给定的站点并回到原处,请问最少需要多少时间?你可以指定的初始方向。
做法
通过分类讨论,我们可以知道最终情况只有以下四种。
每种情况分别通过二分计算即可。
这种情况只需要找到最接近最右侧点而且在最右侧点右侧的关键点即可。
这种情况只需要找到能让两侧转变方向的最优关键点即可,对于这个的查询可以直接用lower_bound查询。
当所有点都在同一侧,而且需要的关键点也在同一侧时,可以直接这样走。
代码
#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
vector<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.吃豆豆
题意
有一个行列的棋盘,对于第行第列的格子,每过秒会在上面出现一个糖果,第一次糖果出现在第秒,糖果仅会在出现的那一秒存在,下一秒就会消失。假如第秒在第行第列的格子上,满足,则会得到一个糖果。
假如当前在第行第列的格子上,那么下一秒他可以选择往上下左右走一格或停在原地。
现在请问从指定的出发到达指定的,并且在路上得到至少个糖果最少需要多少时间?
在的初始时间为第秒。
做法
可以看到这道题都很小。
但是这道题的关键在于换一个方向思考问题,我们直接用表示到达点得到k个糖果的最短时间的话,是不能的,因为上一个状态不确定,无法。但是我们可以发现最后的答案一定不会超过,因为我们可以站在一个位置不动,用这些时间就能达到目的,所以我们可用表示到达点经过时间能达到的最大糖果数,这就很容易了。只要从的能到达本点的状态去转移即可。最后找到能到在终点能得到个糖果的最短时间即可。
代码
#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拆成, 把B拆成, 满足
1.对于所有的
2.
如果有多组满足条件的和,请输出最小的任意一组即可。
如果无解,请输出。
做法
首先如果两个数本来就是互质的,只分成一组即可
其余的情况我们猜测分为两组即可
首先我们找到第一个不是的因子也不是的因子的质数
然后这样拆分
因为不是的倍数,所以不是的倍数,所以
因为不是的倍数,所以不是的倍数,所以
因为前15个质数相乘就已经大于 ,所以枚举到第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;
}
题意
做法
代码
题意
做法
代码
题意
做法
代码
题意
做法
代码