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

前言


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


题解


A.机器人

题意

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

做法

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

题意

wlswls有一个nnmm列的棋盘,对于第ii行第jj列的格子,每过T[i][j]T[i][j]秒会在上面出现一个糖果,第一次糖果出现在第T[i][j]T[i][j]秒,糖果仅会在出现的那一秒存在,下一秒就会消失。假如wlswlskk秒在第ii行第jj列的格子上,满足T[i][j]kT[i][j] | k,则wlswls会得到一个糖果。
假如当前wlswls在第ii行第jj列的格子上,那么下一秒他可以选择往上下左右走一格或停在原地。
现在请问wlswls从指定的SS出发到达指定的TT,并且在路上得到至少CC个糖果最少需要多少时间?
wlswlsSS的初始时间为第00秒。
1n,m,T[i][j]101≤n,m,T[i][j]≤10
1C10181 \leq C \leq 1018
做法

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

代码

#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.拆拆拆数

题意

读入ABA和B,wlswls想请你把A拆成a1,a2,a3...,ana_1,a_2,a_3...,a_n, 把B拆成b1,b2.b3...,bnb_1,b_2.b_3...,b_n, 满足
1.对于所有的i(1in),ai,bi2gcd(ai,bi)=1i(1 \leq i \leq n),a_i,b_i \ge 2且gcd(a_i,b_i) = 1
2.Σi=1nai=A,Σi=1nbi=B\varSigma _{i=1}^{n}a_i=A,\varSigma _{i=1}^{n}b_i=B
如果有多组满足条件的aabb,请输出nn最小的任意一组即可。
如果无解,请输出1−1
5A,B10185 \leq A,B \leq 10^{18}
做法

首先如果两个数本来就是互质的,只分成一组即可
其余的情况我们猜测分为两组即可
首先我们找到第一个不是AA的因子也不是BB的因子的质数PP
然后这样拆分A,BA,B
AP    PA-P \ \ \ \ P
P           BPP \ \ \ \ \ \ \ \ \ \ \ B-P
因为AA不是PP的倍数,所以APA-P不是PP的倍数,所以gcd(AP,P)=1gcd(A-P,P)=1
因为BB不是PP的倍数,所以BPB-P不是PP的倍数,所以gcd(P,BP)=1gcd(P,B-P)=1
因为前15个质数相乘就已经大于101810^{18} ,所以枚举到第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;
}


题意

做法

代码



题意

做法

代码



题意

做法

代码



题意

做法

代码


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章