0
点赞
收藏
分享

微信扫一扫

安徽工程大学校赛题解

妖妖妈 2022-03-26 阅读 15

安徽工程大学校赛题解

P1 三国杀
考点:if判断
难度:签到;
题解:因为不知道小B的手牌是什么,但要确定小A必胜,考虑小B的m张手牌都是桃即可,所以就是问n张杀可以把一个生命值为m+k的人击败。
代码如下:

void solve(){
    int n,m,k;
   	scanf("%d %d %d",&n,&m,&k);
   	if(n>=m+k){
   		puts("YES");
	}else{
		puts("NO");
	}
}

P2 打地鼠
考点:循环计数
难度:本意是签到,结果有点惨
解题:分析题意,就是循环时遇到5就不处理,除了5的数字,5计数加一,其他数字计数加一。
代码如下:

void solve(){
    int n,x;
    int cnt[20]={0};
   	scanf("%d",&n);
   	for(int i=1;i<=n;i++){
   	    scanf("%d",&x);
   	    if(x==5) continue;      //若是5,原地击球,不会移动
   	    cnt[x]++;               //经过x的位置,路过x的次数加一
   	    cnt[5]++;               //回到5的位置,经过加一
   	}
   	for(int i=1;i<=9;i++){
   	    printf("%d ",cnt[i]);
   	}
}

P3 进入校园
考点:分类讨论,ifelse。
难度:简答(但略微有些细节):
做法:分析题目,有个重要细节就是,m<=n;
所以分三类,一类是n等于m,那么所有人都可以一次进入学校,输出1;第二类是,n不等于m,但m等于1,由于至少需要一个人把卡,带出来,这是一个无解的情况,输出-1;第三类就是剩余情况,n个人,m张卡,假设最后一次,一定是m个人一起进入校园(这里是一次),那么现在就是n-m个人,每次进入m-1个人,问需要多少次,每次乘以2(因为来回),所以就是(n-m)除(m-1)上取整,
这里提一下,计算机语言中,整型只有整除,所以对于a除b上取整就是(a+b-1)/b。那么到这里,问题就解决了。
代码如下:

void solve(){
    int n,m;
    scanf("%d %d",&n,&m);
    if(n==m){           //n个人有m张卡,直接
        printf("1\n");
    }else if(m==1){     
        printf("-1\n");
    }else{
        n-=m;       //假设最后一次进去m个人;
        int cnt=1;
        cnt+=(n+m-2)/(m-1)*2; //n个人,每次进入m-1个,然后保证上取整
        printf("%d\n",cnt);
    }
}
 
int main(){
    int T;
    scanf("%d",&T);
    while(T--)solve();
    return 0;
}

P4
考点:差分,前缀和,枚举
题解:如果是在暴力的情况,直接枚举每个区间,然后进行涂色,最后暴力枚举,计算符合要求的数量即可,但是由于次数过多,会超时,所以要用到算法(差分)。然后这里有一个技巧,就是一步处理这种区间加的方法,就是差分。
代码如下:

void solve(){
    int n,m;
    scanf("%d %d",&n,&m);
    int w[N][2]={0};
    for(int i=1;i<=n;i++){
    	int op,x;
        scanf("%d %d",&op,&x); 
        if(op==1){
            w[x][0]++,w[x+m][0]--;
        }else{
            w[x][1]++,w[x+m][1]--;
        }
    }
    int t0=0,t1=0,res=0;
    for(int i=1;i<N;i++){
        t0+=w[i][0];
        t1+=w[i][1];
        if(t0&&!t1) res++;
    }
    cout<<res<<endl;
}

P5
考点:爆搜,二进制枚举,贪心

在这里插入代码片

P6
考点:并查集,离线操作;
难度:中等。
做法:用并查集先把所有友好关系处理,把他们合并到不同的集合内,把所有矛盾关系,拉的后面处理,再判断所有矛盾关系是否在一个集合内,若在一个集合内,则无法组队,若不在一个集合内,则可以组队。

#include<bits/stdc++.h>
using namespace std;

const int N=200010,mod=1e9+7;

struct node{
    int x,y;
}e[N];

int fa[N];

int find(int x){
    if(x!=fa[x])  fa[x]=find(fa[x]);
    return fa[x];
}
 
int main(){ 
    int n,a,b,c,k=0;	//k记录有矛盾的边
    cin>>n;
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1,a,b,c;i<=n;i++){
        cin>>a>>b>>c;
        if(c==1){
        	a=find(a),b=find(b);
        	if(a!=b) fa[a]=b;
		}else e[k++]={a,b};
    }
    for(int i=0;i<k;i++){
        int pa=find(e[i].x),pb=find(e[i].y);
        if(pa==pb){
            puts("NO");
            return ;
        }
    }
    puts("YES");
    return 0;
}

P7
考点:二分+前缀和
题解:首先发现,ai的值是没有意义的,所以有意义的只有两两之间的差值,然后对差值进行排序,可以发现只有大于k的值才会对答案造成贡献,就是找到第一个大于等于k的值,然后后面每个值减k,然后计算伤害,由于暴力枚举会超时,所以考虑 二分找到第一个大于k的位置,然后用前缀和来计算大于k那一段的和,再减去

大于k的值得数量乘上k,即可算出目标伤害。

#include<bits/stdc++.h>
using namespace std;
 
typedef long long LL;

const int N=200010,mod=1e9+7;

int n,m,k;
int a[N];
LL b[N],s[N];

int main(){ 
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)   scanf("%d",&a[i]);
    for(int i=1;i<n;i++) b[i]=a[i+1]-a[i];
    sort(b+1,b+n);
    for(int i=1;i<=n;i++) s[i]=b[i]+s[i-1];
    while(m--){
        LL x,y;
        scanf("%lld %lld",&y,&x);
        int l=1,r=n-1;
        while(l<r){
            int mid=(l+r)/2;
            if(b[mid]>y) r=mid;
            else l=mid+1;
        }
        if(b[l]<y) l++;
        LL res=s[n-1]-s[l-1]-y*(n-l);
        //cout<<res<<endl;
        if(res>=x) puts("YES");
        else puts("NO");
    }
    return 0;
}

P8
考点:01背包计数,猜结论

#include<bits/stdc++.h>
using namespace std;
 
typedef long long LL;
 
 
const int N=200010,mod=998244353;

int n,m;
int f[N][15];

int change(int x){
    if(x<10) return x;
    int res=0;
    while(x){
        res+= x%10;
        x/=10;
    }
    return change(res);
}

int main(){ 
    scanf("%d",&n);
    f[0][0]=1;
    for(int i=1,x;i<=n;i++){
        scanf("%d",&x);
        x=change(x);
        for(int j=0;j<=9;j++) f[i][j]=f[i-1][j];
        for(int j=0;j<=9;j++){
            int y=change(j+x);
            f[i][y]=(f[i][y]+f[i-1][j])%mod;
        }
    }
    for(int i=1;i<=9;i++) printf("%d ",f[n][i]);
	return 0;
}

P9
考点:离散化,树状数组,二分

#include<bits/stdc++.h>
using namespace std;
 
typedef long long LL;
 
 
const int N=500010,mod=1e9+7;
 
int n,m;
LL tr[N];
LL s1[N],s2[N],s3[N];
vector<LL> alls;
 
inline int lowbit(int x) {
    return x&(-x);
}
void add(int x){
    for(int i=x;i<=n;i+=lowbit(i)) tr[i]++;
}
int sum(int x){
    int ans=0;
    for(int i=x;i>0;i-=lowbit(i)) ans+=tr[i];
    return ans;
}
 
int find(LL x){
    return lower_bound(alls.begin(),alls.end(),x)-alls.begin()+1;
}
 
int main(){ 
    scanf("%d",&m);
    for(int i=1;i<=m;i++)	scanf("%lld %lld %lld",&s1[i],&s2[i],&s3[i]);
    for(int i=1;i<=m;i++) s1[i]+=s1[i-1];
    for(int i=1;i<=m;i++) s2[i]+=s2[i-1];
    for(int i=1;i<=m;i++) s3[i]+=s3[i-1];
    for(int l=1;l<=m;l++){
        alls.push_back(s2[l]+s3[m]-s3[l-1]);
        alls.push_back(s2[l-1]-s1[l]);
    }
    sort(alls.begin(),alls.end());
    alls.erase(unique(alls.begin(), alls.end()), alls.end());
    n=alls.size();
    LL ans=0;
    for(int l=m;l>=1;l--){
        int x=find(s2[l]+s3[m]-s3[l-1]),y=find(s2[l-1]-s1[l]);
        add(x);
        int cnts=sum(n)-sum(y-1);
        ans=(ans+cnts)%mod;
    }
    cout<<ans<<endl;
    return 0;
}
举报

相关推荐

0 条评论