数学课(math)

数学课(math)

数学课(math)

题目描述

 

wzy又来上数学课了…… 虽然他很菜,但是数学还是懂一丢丢的。老师出了一道题,给定一个包含nn个元素的集合P=1,2,3,…,nP=1,2,3,…,n,求有多少个集合A⊆PA⊆P,满足任意x∈Ax∈A有2x∉A2x∉A,且对于AA在PP中的补集BB,也满足任意x∈Bx∈B有2x∉B2x∉B。

wzy花费了1E100天终于算出来了这个答案,但是可恶的caoxia居然又加了一个条件!他要求AA的大小恰好为mm,这样又有多少个AA呢?

这回wzy真的不会了,他找到了你,希望能够得到帮助。由于答案太大,你只需要输出答案mod10000019mod10000019即可。

 

输入

 

第一行两个数,为n,qn,q。接下来qq行每行一个数mm,询问大小为mm的AA一共有多少个。

 

输出

 

共qq行,每行一个数,表示方案数mod10000019

 

样例解释

对于第一个样例,P={1,2,3},P可以选{1},{2},{1,3},{2,3},大小为1的两种,大小为2的也有两种

对于第二个样例,我想到了一个绝妙的解释,可惜这里写不下。

数据范围及约定

subtask1:20pts,n,m,q≤20n,m,q≤20.

subtask2:30pts,n,m,q≤5,000n,m,q≤5,000.

subtask3:30pts,n,m≤10,000,000,q≤100,000n,m≤10,000,000,q≤100,000

subtask4:20pts,n,m≤1018,q≤100,000n,m≤1018,q≤100,000

 

 

来源

noip2018模拟-南外


solution

暴力想法,把每个奇数和他乘上2的若干倍丢进数组

可知我的集合一定要选一半

令x=num/2;

那么如果个数为奇数,可以选x/x+1

为偶数则只能选x个

假设奇数个数的数目为NA,偶数个数为NB,sum为一定得选的个数

答案即C(NA,m-sum)*2^NB

也就是选出m-sum个x+1 nb的可以瞎选(每个两种方案)

注意到模数只有10000019,C(n,m)可以用lucas定理求

lucas忘光。。。

如果n<m可以直接return 0,因为这样子N!一定包括mod

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define mod 10000019
using namespace std;
int q;
ll n,m,x,h[mod+10],ny[mod+10],num[70];
ll work(ll a,ll num){
    ll ans=1;
    while(num){
        if(num&1)ans=ans*a;
        a=a*a;a%=mod;ans%=mod;num>>=1;
    }
    return ans;
}
ll C(int N,int M){
    if(N<M)return 0;
    return h[N]*ny[M]%mod*ny[N-M]%mod;
}
ll Lucas(ll N,ll M){
    if(!M)return 1;
    return Lucas(N/mod,M/mod)*C(N%mod,M%mod)%mod;
}
int main()
{
    cin>>n>>q;
    ll x=2,la=n,cnt=0,sum=0,na=0,nb=0;
    if(la%2==0)la--;
    while(1){
         
        ll now=n/x;
        if(now%2==0)now++;
        else now+=2;
        num[++cnt]=(la-now)/2+1;
        if(cnt&1)na=na+num[cnt];
        else nb=nb+num[cnt];
        sum=sum+num[cnt]*(cnt/2);
        if(now==1)break;la=now-2;x<<=1;
    }
    h[0]=1;for(int i=1;i<mod;i++)h[i]=h[i-1]*i%mod;
    ny[mod-1]=work(h[mod-1],mod-2);
    for(int i=mod-2;i;i--)ny[i]=ny[i+1]*(i+1)%mod;ny[0]=1;
    while(q--){
        scanf("%lld",&m);
        if(m<sum||m>na+sum){puts("0");continue;}
        ll ans=Lucas(na,m-sum)*work(2,nb)%mod;
        ans=(ans+mod)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted @ 2018-11-04 20:44 liankewei 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用以下代码实现: ``` math = float(input("请输入数学成绩:")) english = float(input("请输入英语成绩:")) c = float(input("请输入C语言成绩:")) sum = math + english + c aver = sum / 3 print("总成绩为:", sum) print("平均成绩为:", aver) ``` 运行程序后,会提示用户输入数学、英语和C语言的成绩,然后计算总成绩和平均成绩,并输结果。 ### 回答2: 要编写这个程序,我们首先需要定义三个变量来存储学生的数学、英语和c语言成绩,可以将它们命名为math、english和c,或者用其他更加具有意义的名称。 然后,我们需要计算这三门课的总成绩。可以使用一个变量sum来存储总成绩,每次将该学生的三门课成绩相加,并将结果存储到sum中。 计算平均成绩的方法也相对简单。我们可以先将总成绩除以3得到平均成绩,然后将结果存储到一个变量aver中。 接下来,我们就可以输这个学生三门课的总成绩与平均成绩了。可以使用printf函数将它们输到屏幕上,也可以将它们输到文件中。 下面给一个示例程序,实现了以上的功能: #include <stdio.h> int main() { int math, english, c; int sum; float aver; // 读入三门课成绩 printf("请输入数学、英语和c语言成绩:\n"); scanf("%d %d %d", &math, &english, &c); // 计算总成绩 sum = math + english + c; // 计算平均成绩 aver = (float) sum / 3; // 输总成绩和平均成绩 printf("总成绩:%d\n", sum); printf("平均成绩:%.2f\n", aver); //保留两小数 return 0; } 该程序首先提示用户输入数学、英语和c语言成绩,并使用scanf函数将它们读入到相应的变量中。然后计算总成绩和平均成绩,并使用printf函数将它们输到屏幕上。程序最后返回0,表示正常结束。 ### 回答3: 为了编写程序输入某学生的数学、英语和c语言的成绩,需要先确定输入方式。可以使用input()函数输入数学、英语和c语言的成绩,例如: math = input("请输入数学成绩:") english = input("请输入英语成绩:") c = input("请输入C语言成绩:") 接下来需要将输入的成绩转换为数值型数据类型以便进行计算。可以使用float()函数将输入的字符串转换为浮点型数据类型。代码如下: math = float(input("请输入数学成绩:")) english = float(input("请输入英语成绩:")) c = float(input("请输入C语言成绩:")) 接下来可以对数学、英语和c语言的成绩进行求和,然后计算平均成绩。求和可以使用加法运算符,计算平均成绩可以使用除法运算符。代码如下: sum = math + english + c aver = sum / 3 最后,可以通过print()函数输该学生这三门课的总成绩和平均成绩。代码如下: print("总成绩:", sum) print("平均成绩:", aver) 完整代码如下: math = float(input("请输入数学成绩:")) english = float(input("请输入英语成绩:")) c = float(input("请输入C语言成绩:")) sum = math + english + c aver = sum / 3 print("总成绩:", sum) print("平均成绩:", aver)

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值