CCPC-Wannafly Winter Camp Day4 (Div2, onsite)

目录

 

A.夺宝奇兵

C.最小边覆盖

D.欧拉回路

F.小小马

G.置置置换

I.咆咆咆哮

K.两条路径


A.夺宝奇兵

两两之间的距离就两种情况,取一下最小值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e5+7;
struct Node{
    ll x,y;
}a[2][N];
int main()
{
    ll n,m;
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++){
        for(ll j=0;j<=1;j++){
            scanf("%lld%lld",&a[j][i].x,&a[j][i].y);
        }
    }
    ll ans=0;
        for(ll i=1;i<n;i++){
            ll la=abs(a[0][i].x-a[0][i+1].x)+abs(a[0][i].y-a[0][i+1].y)+abs(a[1][i].x-a[1][i+1].x)+abs(a[1][i].y-a[1][i+1].y);
            ll lb=abs(a[1][i].x-a[0][i+1].x)+abs(a[1][i].y-a[0][i+1].y)+abs(a[0][i].x-a[1][i+1].x)+abs(a[0][i].y-a[1][i+1].y);
            ans+=min(la,lb);
        }
    ans+=abs(a[0][n].x-a[1][n].x)+abs(a[0][n].y-a[1][n].y);
    printf("%lld\n",ans);
    return 0;
}

C.最小边覆盖

存在长度大于等于3的链即不合法。然后搜....搜一下也过了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+7;
const int M=3e5+7;
struct Edge{
    int v,nxt;
    Edge(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[N*2];
int p[N],edn;
void add(int u,int v){
    e[++edn]=Edge(v,p[u]);p[u]=edn;
    e[++edn]=Edge(u,p[v]);p[v]=edn;
}
int n,m;
struct Node{
    int id,fa,stp;
    Node(int id,int fa,int stp):id(id),fa(fa),stp(stp){}
};
bool vis[N];
int d[N];
bool dfs(int u,int f,int stp){
    vis[u]=true;
    if(stp==3) return 0;
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(v==f) continue;
        if(!dfs(v,u,stp+1)) return false;
    }
    return true;
}
int main()
{
    memset(p,-1,sizeof(p));edn=-1;
    scanf("%d%d",&n,&m);
    int u,v;
    for(int i=1;i<=m;i++){
        scanf("%d%d",&u,&v);
        d[u]++;d[v]++;
        add(u,v);
    }
    bool flag=false;
    for(int i=1;i<=n;i++){
        if(d[i]==1){
            flag=true;
            if(dfs(i,-1,0)) continue;
            printf("No\n");
            return 0;
        }
    }
    if(!flag) printf("No\n");
    else printf("Yes\n");
    return 0;
}

D.欧拉回路

留坑


F.小小马

马走日,所以每走一步的颜色肯定不一样,也就是说终点和起点的颜色肯定要不一样。然后就是马能不能走到的问题了,棋盘足够大肯定都能走到,棋盘小就搜一下就行了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e3+7;
int sx,sy,ex,ey;
struct Node{
    int x,y,stp;
    Node(int x,int y,int stp):x(x),y(y),stp(stp){}
};
int n,m;
int dir[8][2]={2,1,2,-1,-2,1,-2,-1,1,2,1,-2,-1,2,-1,-2};
bool vis[N][N];
bool bfs(){
    queue<Node>q;
    q.push(Node(sx,sy,0));
    while(!q.empty()){
        Node t=q.front();q.pop();
        vis[t.x][t.y]=true;
        for(int k=0;k<8;k++){
            int dx=t.x+dir[k][0];
            int dy=t.y+dir[k][1];
            if(dx<1||dx>n||dy<1||dy>m) continue;
            if(vis[dx][dy]) continue;
            if((dx==ex)&&(dy==ey)&&(t.stp%2==0)) return true;
            q.push(Node(dx,dy,t.stp+1));
        }
    }
    return false;
}
int main()
{

    scanf("%d%d",&n,&m);
    scanf("%d%d%d%d",&sx,&sy,&ex,&ey);
    if(((sx%2)==(sy%2))==((ex%2)==(ey%2))){
        printf("No\n");
        return 0;
    }
    if(n>=100&&m>=100){
        printf("Yes\n");
        return 0;
    } 
    if(bfs()) printf("Yes\n");
    else printf("No\n");
    return 0;
}

G.置置置换

dp[i][j]表示第i位放数字j的情况,sum[i][j]dp数组的前缀和,即:sum[i][j]=\sum _{k=1}^jdp[i][k]

要考虑到,第i位放任何一个数字,前面都是i-1个数字的排列关系,所以dp[i]是可以通过sum[i-1]来转移的,剩下唯一要考虑的是要不要-1,想清楚的话就过了。

答案据说可以三分,然后可以过div1.

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const ll N=2e3+7;
ll dp[N][N];
ll sum[N][N];
int main()
{
    ll n;
    scanf("%lld",&n);
    dp[1][1]=1;
    for(ll i=1;i<=n;i++) sum[1][i]=1;
    for(ll i=2;i<=n;i++){
        for(ll j=1;j<=i;j++){
            if(i%2==0) dp[i][j]=(sum[i-1][i-1]-sum[i-1][j-1]+mod)%mod;
            else dp[i][j]=sum[i-1][j-1];
            sum[i][j]=(sum[i][j-1]+dp[i][j])%mod;
        }
    }
    printf("%lld\n",sum[n][n]);
    return 0;
}

I.咆咆咆哮

首先肯定先放怪,再加攻。枚举放几张怪,每张卡对于这种情况的贡献也就可以算出来,然后贪心的枚举,取最大值即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e3+7;
struct Node{
    ll a,b,val;
    bool operator<(const Node t){
        return val>t.val;
    }
}ar[N];
int main()
{
    ll n;
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++){
        scanf("%lld%lld",&ar[i].a,&ar[i].b);
    }
    ll ans=0;
    for(ll k=1;k<=n;k++){
        for(ll i=1;i<=n;i++){
            ar[i].val=ar[i].a-ar[i].b*k;
        }
        sort(ar+1,ar+1+n);
        ll tmp=0;
        for(ll i=1;i<=k;i++) tmp+=ar[i].a;
        for(ll i=k+1;i<=n;i++) tmp+=k*ar[i].b;
        ans=max(ans,tmp);
    }
    printf("%lld\n",ans);
    return 0;
}

K.两条路径

对于询问的每个点u,找出四条最大的、以u为端点的、互不相交的链就是答案。对与u相连的所有点做树形dp即可,剩下的就是注意一下输入输出。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=2e5+7;
ll dp[N],a[N];
struct Edge{
    ll v,nxt;
}e[N*2];
ll p[N],edn;
void add(ll u,ll v){
    e[++edn]=(Edge){v,p[u]};p[u]=edn;
    e[++edn]=(Edge){u,p[v]};p[v]=edn;
}
ll val[N];
ll dfs(ll u,ll f){
    ll res=0;
    for(ll i=p[u];~i;i=e[i].nxt){
        ll v=e[i].v;
        if(v==f) continue;
        res=max(dfs(v,u),res);
    }
    return res+a[u];
}
ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res*=a;
        a*=a;b>>=1;
    }
    return res;
}
ll pri[N];
int main()
{
    ll n;
    scanf("%lld",&n);
    memset(p,-1,sizeof(p));edn=-1;
    for(ll i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        if(a[i]>0) a[i]=qpow(2,a[i]-1);
        else if(a[i]<0) a[i]=-qpow(2,-a[i]-1);
    }
    ll u,v;
    for(ll i=1;i<n;i++){
        scanf("%lld%lld",&u,&v);
        add(u,v);
    }
    ll q;
    scanf("%lld",&q);
    while(q--){
        scanf("%lld",&u);
        ll tot=0;
        for(ll i=p[u];~i;i=e[i].nxt){
            ll v=e[i].v;
            val[++tot]=dfs(v,u);
        }
        sort(val+1,val+1+tot);
        ll ans=0;
        for(ll i=tot;i>=tot-3&&i>=1;i--){
            if(val[i]>0) ans+=val[i];
            else break;
        }
        ans+=a[u];
        if(ans==0) printf("0\n");
        else{
            if(ans<0){
                printf("-");
                ans=-ans;
            }
            tot=0;
            while(ans){
                pri[++tot]=ans%2;
                ans/=2;
            }
            for(ll i=tot;i>=1;i--){
                printf("%lld",pri[i]);
            }
            printf("\n");
        }
    }
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值