北京化工大学2022-2023-1 ACM集训队每周程序设计竞赛(2)题解

xsyの末日!

按照题意直接模拟即可

当n大于10时,输出q

n小于10时,输出q+100*(10-n)

signed main()
{
  int n,q;
  scanf("%lld%lld",&n,&q);
  if(n>=10) printf("%lld\n",q);
  else printf("%lld\n",q+100*(10-n));
  return 0;
}

B 今天猛犸不上班

求数字n在k进制下的位数

其实就是看n除k可以除几次除成0呗

比如10000在十进制是五位数,那就可以除五次十

代码如下

signed main() {
    int n,k,ans=0;
    cin>>n>>k;
    while(n) {
        n/=k;
        ans++;
    }
    cout<<ans;
    return 0;
}

C 你干嘛 哈哈嗨呦

这道题其实仔细看题面就能发现简单的解法

位置数和n只有100个,我们可以直接n^{2}暴力每一个位置,在取min就好了

代码如下

const int N=105;
int a[N];
int main() {
    int n,ans=1e9;
    scanf("%d",&n);
    for(int i=0,x;i<n;i++) {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=100;i++) {
        int s=0;
        for(int j=0;j<n;j++) {
            s+=(a[j]-i)*(a[j]-i);
        }
        ans=min(ans,s);
    }
    printf("%d\n",ans);
    return 0;
}

D 重生之我是菜狗

题意可以抽象为,从n只中选x只,不能选a只或b只

大家知道,从n只中选i只,答案为2^{n}种,排除不选,也就是2^{n}-1

不能选a只或b只,就从答案中减去 \binom{n}{a}\binom{n}{b}

代码如下

const int N=3e5+10;
const int mod=1e9+7;
int qpow(int x,int y) {
    int ans=1;
    while(y) {
        if(y&1) ans=ans*x%mod;
        y>>=1;
        x=x*x%mod;
    }
    return ans;
}
void add(int &x,int y) {
    x+=y;
    if(x>=mod) x-=mod;
    if(x<0) x+=mod;
}
signed main() {
    int n,a,b;
    cin>>n>>a>>b;
    int ans=qpow(2,n),s=1;
    add(ans,-1);
    for(int i=1;i<=b;i++) {
        s=1LL*s*(n-i+1)%mod,s=1LL*s*qpow(i,mod-2)%mod;
        if(i==a) add(ans,-s);
        if(i==b) add(ans,-s);
    }
    cout<<ans<<endl;
    return 0;
}

E 这隔离点网太烂了!

比较复杂的排列组合

分开考虑有没有房间人数为0

1.没有房间为0的移法

2.有且只有一个房间为0的移法

3.超过一个房间为0的移法

将n个人分到n-i的房间   可以这样计算  

n个人之间可放入n-1个隔板,因要分成n-i份,需要插入n-i-1个隔板

\binom{n-1}{n-i-1}=\binom{n-1}{i}

选出i个房间空出来,选法有\binom{n}{i}

所以对于每一个空出房间数i,有\binom{n}{i}*\binom{n-1}{i}

总的答案为

\sum_{i=0}^{min(k,n-1)}\binom{n}{i}*\binom{n-1}{i}

代码如下

const int N=3e5+10;
const int mod=1e9+7;
int f[N],inv[N];
int qpow(int a,int b){
	int ret=1;
	while(b){
		if(b&1)ret=ret*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ret;
}
int C(int n,int m){
	int ans;
	ans=f[n]*inv[n-m]%mod*inv[m]%mod;
	return ans;
}
signed main(){
	int n,k,i,ans=0;
	cin>>n>>k;

	f[0]=1;
	for(i=1;i<=n;i++)f[i]=f[i-1]*i%mod;
	for(i=0;i<=n;i++)inv[i]=qpow(f[i],mod-2)%mod;
    //预处理大组合数

	k=min(k,n-1);
	for(i=0;i<=k;i++)
		ans=(ans+C(n,i)*C(n-1,i)%mod)%mod;
	cout<<ans;
	return 0;
}

F 计信狗的大一下

题目要求a[i]%m<a[i+1]%m的数目

我们可以转化一下求总数减去a[i]%m=a[i+1]%ma[i]%m>a[i+1]%m

可以先将di对m取模,这样di是一个小于m的数。

根据公式,可以可以推出如下表达式 

第二类的具体推到过程

要使得a_{i}%m>a_{i+1}%m

因为d>0

a_{i+1}>a_{i}

\left \lfloor \frac{a_{i+1}}{m} \right \rfloor>\left \lfloor \frac{a_{i}}{m} \right \rfloor

又因d_{i}<m

\left \lfloor \frac{a_{i+1}}{m} \right \rfloor-\left \lfloor \frac{a_{i}}{m} \right \rfloor=1

所以我们可以从a0开始递推到an-1

int d[5005],zero[5005];//zero[i]累计di=0个数 
int a[5005];//a[i]累计d
signed main()
{
	int k,q;
    cin>>k>>q;
	for(int i=0;i<k;++i) cin>>d[i];
	while(q--)
	{
		int n,x,m,sum,sumzero,sumn;
		cin>>n>>x>>m;
		x%=m;a[0]=0;zero[0]=0; 
		for(int i=0;i<k;++i)
		{
			a[i+1]=a[i]+d[i]%m;
			zero[i+1]=zero[i]+(d[i]%m==0); 
		}//以k为一个循环重复累加 
		sumzero=(n-1)/k*zero[k]+zero[(n-1)%k];//共有(n-1)/k次d的循环加上剩下的(n-1)%k
		sum=((n-1)/k*a[k]+a[(n-1)%k]+x)/m-x/m;
		sumn=(n-1)-sum-sumzero;
		cout<<sumn<<'\n'; 
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值