Avito Cool Challenge 2018

本文解析了五道编程竞赛题目,包括确定游戏结果、派对帽子颜色分配、彩色砖块排列、最大距离计算和缺失数字查找。每题提供算法思路与C++代码实现,涉及数学、贪心算法、动态规划、图论和搜索技巧。

A. Definite Game

题意:给出一个n,每次减去一个t(t<n&&t不是n的除数),问最终的最小结果

解法:n与n-1互质,对2进行特判即可

#include<bits/stdc++.h>
using namespace std;
int main(){
    int n;scanf("%d",&n);
    if(n>2) printf("1\n");
    else printf("%d\n",n);
    return 0;
}
 
View Code

B. Farewell Party

题意:每个人有一顶帽子,有一定的颜色,每个人给出ai,代表帽子颜色与自己不同的人数,求构造n个人帽子的颜色

解法:每个人可以知道有多少人的帽子颜色跟自己相同,排序之后一块一块操作就好,不满足就输出-1即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int b[N];
struct node{int v,id;}a[N];
bool cmp(node a,node b){return a.v<b.v;}
int main(){
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i].v),a[i].id=i;
    sort(a+1,a+n+1,cmp);int f=1,pre=-1;
    int tmp=0;
    for(int i=1;i<=n;){
        int num=n-a[i].v;
        if(a[i+num-1].v==a[i].v){
            tmp++;
            for(int j=i;j<i+num;j++) b[a[j].id]=tmp;
            i+=num;
        }
        else {f=0;break;}
    }
    if(!f) printf("Impossible\n");
    else{
        printf("Possible\n");
        for(int i=1;i<=n;i++) if(i==1) printf("%d",b[i]);else printf(" %d",b[i]);
        printf("\n");
    }
    return 0;
}
View Code

C. Colorful Bricks

题意:n个连续的brick,m中颜色,求有k个brick与自己左边颜色不同的方案数

解法:

  1.可以发现是将这n个bricks分成k+1份,相邻颜色不同,即可得出答案C(n-1,k)*m*(m-1)^k +特判;

  2.dp  dp[i][j]=dp[i-1][j]+dp[i-1][j-1]*(m-1)

  

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
ll pow_(ll a,ll b){
    ll res=1,tmp=a;
    while(b){
        if(b&1) (res*=tmp)%=mod;
        b/=2;
        (tmp*=tmp)%=mod;
    }
    return res;
}
int main(){
    ll n,m,k;scanf("%lld%lld%lld",&n,&m,&k);
    if(m==1) {
        if(k==0) {printf("1\n");return 0;}
        else {printf("0\n");return 0;}
    }
    ll t1=1,t2=1,t3=1,t4=1,t5=1;
    for(ll i=1;i<=n-1;i++) t1=t1*i%mod;
    for(ll i=1;i<=k;i++) t2=t2*i%mod;
    for(ll i=1;i<=n-1-k;i++) t3=t3*i%mod;
    ll ans=t1;
    (ans*=pow_(t2,mod-2))%=mod;
    (ans*=pow_(t3,mod-2))%=mod;
    (ans*=m)%=mod;
    (ans*=pow_(m-1,k))%=mod;
    printf("%lld\n",ans);
    return 0;
}
View Code

D. Maximum Distance

题意:给定一个图,给出k个特殊点,定义路径的长度=max(边权),定义点之间的距离=min(路径),对于每个特殊点,求到其他特殊点的最大距离

解法:因点之间的距离是min(路径),即最大值最小,即让这k个点相互连通,且最大的边最小,即构造这k个点的额最小生成树;因无法直接构造这

k个点的最小生成树,所以考虑在构造n个点的最小生成树的同时,构造这k个点的联通,当这k个点恰好联通的时候,即可输出答案;

  赛场上:没想到简单的写法,就这届构造了最小生成树的图,然后考虑每个点的子树是否有特殊点,这样判断是否向下搜索,寻找最大边

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,k;
struct node{int f,t,c;}b[N];
bool cmp(node a,node b){return a.c<b.c;}; 
int a[N],fa[N];
typedef pair<int,int> pii;
vector<pii>g[N];int x;
int find(int x){
    if(fa[x]==x) return x;else return fa[x]=find(fa[x]);
}
void unite(int x,int y){x=find(x),y=find(y);fa[x]=y;}
int num[N];
void dfs(int x,int fa){
    if(a[x]) num[x]=1;
    for(auto it:g[x]){
        int y=it.first,c=it.second;
        if(y==fa) continue;
        dfs(y,x);
        num[x]+=num[y];
    }
}
int max_=0;
void dfs2(int x,int fa){
    if(num[x]==0) return;
    for(auto it:g[x]){
        int y=it.first,c=it.second;
        if(y==fa) continue;
        if(num[y]!=0) max_=max(max_,c),dfs2(y,x);
    }
}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) fa[i]=i;int s=-1;
    for(int i=1;i<=k;i++) scanf("%d",&x),s=x,a[x]=1;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&b[i].f,&b[i].t,&b[i].c);
    sort(b+1,b+m+1,cmp);int num_=0;
    for(int i=1;i<=m;i++){
        int x=b[i].f,y=b[i].t;
        if(find(x)!=find(y)) {    
            unite(x,y);num_++;
            g[x].push_back({y,b[i].c});g[y].push_back({x,b[i].c});
        }
        if(num_==n-1) break;
    }
    //for(int i=1;i<=n;i++) cout<<g[i].size()<<endl;
    dfs(s,-1);dfs2(s,-1);
    //for(int i=1;i<=n;i++) cout<<i<<" "<<num[i]<<endl;
    for(int i=1;i<=k;i++) if(i==1) printf("%d",max_);else printf(" %d",max_);
    printf("\n");
    return 0;
}
赛场
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,k;
struct node{int f,t,c;}b[N];
bool cmp(node a,node b){return a.c<b.c;}; 
int a[N],fa[N];
int x,num[N];
int find(int x){
    if(fa[x]==x) return x;else return fa[x]=find(fa[x]);
}
void unite(int x,int y){x=find(x),y=find(y);fa[y]=x;}
int main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=k;i++) scanf("%d",&x),num[x]=1;
    for(int i=1;i<=m;i++) scanf("%d%d%d",&b[i].f,&b[i].t,&b[i].c);
    sort(b+1,b+m+1,cmp);int ans_=-1;
    for(int i=1;i<=m;i++){
        int x=b[i].f,y=b[i].t;int xx=find(x),yy=find(y);
        if(xx!=yy) {
            fa[yy]=xx;num[xx]+=num[yy];
            if(num[xx]==k) {ans_=b[i].c;break;};
        }
    }
    for(int i=1;i<=k;i++) if(i==1) printf("%d",ans_);else printf(" %d",ans_);
    printf("\n");
    return 0;
}

E. Missing Numbers

题意:给定一个n,偶数位置的数已知,求构造数列使得每个前缀和均为完全平方数

解法:因为前缀和一定是单调递增的,所以直接遍历k,k*k代表当前的前缀和,贪心找最小的满足条件的k即可;

  (说实话。。。标解实在是没看懂,我也没仔细想我这样写为什么是对的,等到和F一块更新吧)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
ll a[N];
bool is_(ll a){ll t=sqrt(a);return t*t==a;}
int main(){
    int n;scanf("%d",&n);
    for(int i=2;i<=n;i+=2) scanf("%lld",&a[i]);
    ll k=0;int i;
    for(i=1;i<=n;i+=2){
        ll pre=k*k;k++;
        while(!is_(k*k+a[i+1])) {k++;if(k>2e6) {printf("No\n"); return 0;}}
        a[i]=k*k-pre;
        k=sqrt(k*k+a[i+1]);
    } 
    printf("Yes\n");
    for(int i=1;i<=n;i++) if(i==1) printf("%lld",a[i]);else printf(" %lld",a[i]);
    printf("\n");
    return 0;
} 
View Code

 

转载于:https://www.cnblogs.com/vainglory/p/10130341.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值