【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;
}


題意

做法

代碼



題意

做法

代碼



題意

做法

代碼



題意

做法

代碼


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