有趣的数列 [Codevs 2337,Bzoj 1485,HNOI2009]

45 篇文章 0 订阅
33 篇文章 0 订阅

题目地址请点击——


有趣的数列


【题目描述】

我们称一个长度为 2n 的数列是有趣的,当且仅当该数列满足以下三个条件:

(1)它是从 1 2n 2n 个整数的一个排列 {ai}

(2)所有的奇数项满足 a1<a3<<a2n1 ,所有的偶数项满足 a2<a4<<a2n

(3)任意相邻的两项 a2i1 a2i ( 1in )满足奇数项小于偶数项,即: a2i1<a2i

现在的任务是:对于给定的 n ,请求出有多少个不同的长度为 2n 的有趣的数列。
因为最后的答案可能很大,所以只要求输出答案 mod P 的值。


【输入描述】

输入文件只包含用空格隔开的两个整数 n P


【输出描述】

仅含一个整数,表示不同的长度为 2n 的有趣的数列个数 mod P 的值。


【样例输入】

3 10


【样例输出】

5


【Solution】

我们将这 2n 个数从小到大排个序,然后从小到大决定每一个数放在奇数位还是偶数位。
好比是两个栈,一个装奇数位的数字,一个装偶数位的数字,然后从小到大扫过每个数,决定它放进哪个栈。
这样,我们就可以满足第一、二个条件了。
第三个条件如何满足呢?
我们发现,装偶数位的数字的栈的元素个数一定要小于或等于装奇数位的数字的栈的元素个数。
为什么呢?因为如果出现违背上面那条原则的情况,那么就会出现:第 2k 个数已经放好了,第 2k+2 个数也已经放好了,而第 2k+1 个数还没有放好(因为放在偶数位上的数字个数比放在奇数位上的数字个数要多)。
而我们是从小到大放的数,所以要放在第 2k+1 上的数一定比第 2k 2k+2 个数要大,不符合第三条情况。
如果我们把放在偶数位上视作 y+1 , 放在奇数位上视作 x+1 ,那么放 2n 个数就可以转化为在平面上从 (0,0) 走到 (n,n)
因为时时刻刻 x>=y ,所以相当于走到 (n,n) 且不可以穿过直线 y=x 的路径总数!
根据我之前写的网格这篇博文,

ans=[Cn2nCn12n] mod p=[(2n)!n!n!(2n)!(n+1)!(n1)!] mod p=[(2n)!(n+1)(2n)!n(n+1)!n!] mod p=(2n)!(n+1)!n! mod p=(2n)(2n1)(n+2)n! mod p=(2n1)(2n3)(n+3)((n+2)21)!2(2n(n+2)+1)/2+1 mod p(2n1)(2n3)(n+2)((n+1)2)!2(2n(n+3)+1)/2+1 mod pn0(mod 2),n1(mod 2).

因为取模的 p 不是素数,所以不能用逆元乱搞了。
我们可以用质因数分解的方法,将答案的唯一分解式算出来。
这里我想到了一个类似分治的方法。
我们可以用筛素数的方法,求出每个数 i 的最小质因子 k 和这个质因子是第几个质数 fi
设唯一分解式的第 i 个质数的指数为 ti,则 tfi 加一,然后分治处理 ik
然后就可以 A 了。


【Code】

[cpp]
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <cstring>  
  4. #include <ctime>  
  5.   
  6. using namespace std;  
  7.   
  8. #define LL long long  
  9. typedef LL bign;  
  10.   
  11. LL tt[2000010];  
  12. LL prime[2000010];  
  13. LL first[2000010];  
  14. bool no_prime[2000010];   
  15.   
  16. LL n,m;  
  17. bign ans=1;  
  18.   
  19. LL power(LL x,LL y){  
  20.     if(y==0)return 1;  
  21.     if(y==1)return x%m;  
  22.     LL tmp=power(x%m,y/2);  
  23.     if(y&1)return tmp*tmp%m*(x%m)%m;  
  24.     else return tmp*tmp%m;   
  25. }  
  26.   
  27. void make1(LL x){  
  28.     while(1){  
  29.         if(x==1)return;  
  30.         if(prime[first[x]]==x){  
  31.             tt[first[x]]++;  
  32.             return;   
  33.         }  
  34.         else{  
  35.             while(x%prime[first[x]]==0){  
  36.                 tt[first[x]]++;  
  37.                 x/=prime[first[x]];  
  38.             }  
  39.         }  
  40.     }  
  41. }  
  42.   
  43. void make2(LL x){  
  44.     while(1){  
  45.         if(x==1)return;  
  46.         if(prime[first[x]]==x){  
  47.             tt[first[x]]–;  
  48.             return;  
  49.         }  
  50.         else{  
  51.             while(x%prime[first[x]]==0){  
  52.                 tt[first[x]]–;  
  53.                 x/=prime[first[x]];  
  54.             }  
  55.         }  
  56.     }  
  57. }  
  58.   
  59. void Pyh(){  
  60.     if(!(n&1)){  
  61.         tt[1]=(2*n-(n+2)+1)/2+1;  
  62.         for(LL i=n+3;i<=2*n-1;i+=2)make1(i);  
  63.         for(LL i=2;i<=(n+2)/2-1;i++)make2(i);  
  64.         for(LL i=1;i<=prime[0];i++)ans=ans*power(prime[i]%m,tt[i])%m;  
  65.         printf(”%lld\n”,ans%m);  
  66.     }  
  67.     else{  
  68.         tt[1]=(2*n-(n+3)+1)/2+1;  
  69.         for(LL i=n+2;i<=2*n-1;i+=2)make1(i);  
  70.         for(LL i=2;i<=(n+1)/2;i++)make2(i);  
  71.         for(LL i=1;i<=prime[0];i++)ans=ans*power(prime[i],tt[i])%m;  
  72.         printf(”%lld\n”,ans%m);   
  73.     }  
  74. }  
  75.   
  76. int main(){  
  77.       
  78.     scanf(”%lld%lld”,&n,&m);  
  79.     for(LL i=2;i<=2*n;i++){  
  80.         if(!no_prime[i]){  
  81.             prime[++prime[0]]=i;  
  82.             first[i]=prime[0];  
  83.         }  
  84.         LL j=1,t=i*prime[1];  
  85.         while(j<=prime[0]&&t<=2*n){  
  86.             first[t]=j;  
  87.             no_prime[t]=true;  
  88.             if(i%prime[j]==0)break;  
  89.             t=i*prime[++j];  
  90.         }  
  91.     }   
  92.     Pyh();  
  93.     return 0;  
  94. }  
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
BZOJ 2908 题目是一个数据下载任务。这个任务要求下载指定的数据文件,并统计文件中小于等于给定整数的数字个数。 为了完成这个任务,首先需要选择一个合适的网址来下载文件。我们可以使用一个网络爬虫库,如Python中的Requests库,来帮助我们完成文件下载的操作。 首先,我们需要使用Requests库中的get()方法来访问目标网址,并将目标文件下载到我们的本地计算机中。可以使用以下代码实现文件下载: ```python import requests url = '目标文件的网址' response = requests.get(url) with open('本地保存文件的路径', 'wb') as file: file.write(response.content) ``` 下载完成后,我们可以使用Python内置的open()函数打开已下载的文件,并按行读取文件内容。可以使用以下代码实现文件内容读取: ```python count = 0 with open('本地保存文件的路径', 'r') as file: for line in file: # 在这里实现对每一行数据的判断 # 如果小于等于给定整数,count 加 1 # 否则,不进行任何操作 ``` 在每一行的处理过程中,我们可以使用split()方法将一行数据分割成多个字符串,并使用int()函数将其转换为整数。然后,我们可以将该整数与给定整数进行比较,以判断是否小于等于给定整数。 最后,我们可以将统计结果打印出来,以满足题目的要求。 综上所述,以上是关于解决 BZOJ 2908 数据下载任务的简要步骤和代码实现。 希望对您有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值