安徽工程大学校赛题解
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;
}