vijos 2035 奇数偶数与绚丽多彩的数

描述

Q先生是一个热爱学习的男孩子。

他认为一个 n 位的正整数 x 若能被称作是绚丽多彩的,一定要满足对于{1,3,5,7,9} 中任意一个奇数或者没有在 x 中出现,或者在 x 中出现了恰好奇数次;同时对于 {0,2,4,6,8} 中任意的偶数或者没有在 x 中出现,或者在x 中出现了偶数次。同时需要注意 x 是不能有前导零的。

例如 141221242 就是一个九位的绚丽多彩的数。

现在Q先生给定了正整数 n 与另外一个正整数 p,希望你统计出来一共有多少不超过 n 位的绚丽多彩的数,并输出模 p后的余数。

格式

输入格式

输入有一行,包含两个由空格隔开的正整数,分别为 n 和 p。

输出格式

输出一个正整数,表示不超过 n 位的绚丽多彩数的总数模 p 后的余数。

样例1

样例输入1

7 1000000123

样例输出1

287975

样例2

样例输入2

100 1000000123

样例输出2

123864868

限制

对于100%的数据,2<=n<=2^60,10^9<=p<=2*10^9。

昨晚打的某个比赛的题。

我们发现偶数出现偶数次和不出现都等价于出现的次数%2=0,奇数出现奇数次相当于出现次数%2=1,当然奇数还可能不出现。所以我们可以枚举哪些奇数是不出现的,然后剩下的奇数满足出现奇数次,偶数出现偶数次就行了。

还可以发现我们没有必要知道每个奇数/偶数出现的次数的奇偶性,只需要知道有多少个 奇数/偶数 出现 奇数/偶数 次就行了。也就是状态压缩之后,我们只需要一个两位的五进制数就可以表示一个状态。

而我们在外层也可以直接枚举有几个奇数出现过,然后再将这种情况下的方案总数乘上一个组合数就行了。

但是这个题要求的数是<=n位的没有前导零的满足条件的数的个数,所以我们要求的最终转移方阵不是某个方阵A的n-1次方,而是A^0+A^1+....A^(n-1)。这个推一推式子就可以用类似矩阵快速幂的方法求出。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
ll N,P,n,ans=0,C[10][10];

inline ll add(ll x,ll y){
	x+=y;
	return x>=P?x-P:x;
}

struct node{
	ll a[41][41];

	inline void clear(){
		memset(a,0,sizeof(a));
	}

	inline void init(){
		clear();
		for(int i=0;i<n;i++) a[i][i]=1;
	} 

	node operator *(const node &u)const{
		node r;
		r.clear();
		for(int k=0;k<n;k++)
		    for(int i=0;i<n;i++)
		        for(int j=0;j<n;j++) r.a[i][j]=add(r.a[i][j],a[i][k]*(ll)u.a[k][j]%P);
		return r;
	}

	node operator +(const node &u)const{
		node r;
		for(int i=0;i<n;i++)
		    for(int j=0;j<n;j++) r.a[i][j]=add(a[i][j],u.a[i][j]);
		return r;
	}
}base,ANS;

inline node ksm(node x,ll y){
	node r,q,BA=x; r.init(),q.init();
	int i=60;
	for(;i;i--) if((1ll<<i)&y) break;
	r=x,i--;
	for(;i>=0;i--)
	    if((1ll<<i)&y){
	    	node O=x*BA;
	    	r=r*(q+O)+O;
	    	x=x*O;
		}
		else{
			r=r*(q+x);
			x=x*x;
		}

	return r+q;
}

inline void solve(){
	for(int i=0;i<=5;i++){
		base.clear();
		n=(i+1)*6;
		for(int j=0,X,Y;j<n;j++){
			X=j%6,Y=j/6;
			if(X) base.a[j][j-1]=X;
			if(X<5) base.a[j][j+1]=5-X;
			if(Y) base.a[j][j-6]=Y;
			if(Y<5) base.a[j][j+6]=i-Y;
		}

		ANS=ksm(base,N-1);
		ans=add(ans,C[5][i]*(ll)((4*ANS.a[1][i*6]+i*ANS.a[6][i*6])%P)%P);
	}

	printf("%lld\n",ans);
}

int main(){
	C[0][0]=1;
	for(int i=1;i<=5;i++){
		C[i][0]=1;
		for(int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];
	}
	scanf("%lld%lld",&N,&P);
	solve();
	return 0;
}

  

原文地址:https://www.cnblogs.com/JYYHH/p/8645367.html

时间: 2024-10-11 23:23:18

vijos 2035 奇数偶数与绚丽多彩的数的相关文章

给出一个区间[a, b],计算区间内“神奇数”的个数。 神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数。 比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数。同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数。

给出一个区间[a, b],计算区间内"神奇数"的个数.神奇数的定义:存在不同位置的两个数位,组成一个两位数(且不含前导0),且这个两位数为质数.比如:153,可以使用数字3和数字1组成13,13是质数,满足神奇数.同样153可以找到31和53也为质数,只要找到一个质数即满足神奇数. 输入描述: 输入为两个整数a和b,代表[a, b]区间 (1 ≤ a ≤ b ≤ 10000). 输出描述: 输出为一个整数,表示区间内满足条件的整数个数 输入例子: 11 20 输出例子: 6 1 #in

用if else判断奇数偶数.

1 public class 判断奇数偶数 { 2 3 public static void main(String[] args) { 4 5 int num=14; 6 7 if(num%2==0) 8 { 9 System.out.println("num是偶数"); 10 } 11 else 12 { 13 14 System.out.println("num是奇数"); 15 } 16 // TODO 自动生成的方法存根 17 18 } 19 20 } n

9个绚丽多彩的HTML5进度条动画赏析

进度条在网页应用中越来越广泛了,特别是现在的页面异步局部刷新时代,进度条可以让用户更好的等待操作结果.本文要分享9款绚丽多彩的HTML5进度条动画,有很多还是挺实用的,效果也非常不错. 1.CSS3发光进度条动画 超炫酷的样式 这次我们要来分享一款非常炫酷的CSS3进度条动画,其样式风格类似于星球大战里面的那些激光剑效果.页面初始化时,可以设定进度条的值,但是我们也可以利用其配套的借口来动态改变进度条的值,使用起来比较方便.另外以前介绍过一款CSS3 3D进度条,其风格也类似. 在线演示 源码下

Python 符号、&gt;&gt;:右移、 &lt;&lt;:左移、 &amp;:按位与、 |:按位或 (&amp;与实际应用奇数偶数判断,&gt;&gt;右位移可用于计算文件大小)

右移 (>>):1001->100 右移一位就是二进制码去掉一位 3 >> 1 out:1 bin(3): 11 bin(1): 1 A >> B A / (2 ** B): 可用于计算文件大小,比如2048B 的文件  2048 >> 10 ->2M    2048 / (2 ** 10) = 2 左移(<<):1001->10010 左移一位就是在二进制码的最后一位添加一个0 3 << 1 out:6 bin(3

897B. Chtholly&#39;s request#长度为偶数的回文数(模拟)

题目出处:http://codeforces.com/problemset/problem/897/B 题目大意:构造一个题意要求的zcy数之后取模 #include<iostream> using namespace std; int main(){ int n,m; __int64 g,t,sum=0; cin>>n>>m; //关键在于zcy数的构造 //注意到要求长度是偶数 //考虑回文构造 for(int i=1;i<=n;i++){ g=i; t=i;

给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。

//有101个数,其中有50个数出现了两次,有一个数只出现了一次,找出出现一次的数 #include <stdio.h> #include <stdlib.h> int main() { int a[11] = {0}; int i; int n = 0; printf("please input the arr :"); for(i = 0;i < 11;i++) { scanf("%d",&a[i]); } for(i =

c-函数指针(求奇数偶数的和)

1 #include <stdio.h> 2 3 /* 4 编写一个函数,输入 n 为偶数时,调用函数求 1/2+1/4+...+1/n,当输入 n 为奇数时,调用函数1/1+1/3+...+1/n(利用指针函数). 5 */ 6 7 //1/2 + 1/4 +...+ 1/n; 8 float 9 even(int n) { 10 float sum = 0; 11 for(int i = 2; i <=n; i+=2) 12 sum += (float)1 / i; 13 retur

c++第五次上机实验:项目一-奇数偶数分组

一.问题及代码 /* * 文件名称: * 作 者:刘伟 * 完成日期:2016 年 5月 10日 * 版 本 号:v1.0 * 对任务及求解方法的描述部分: * 输入描述:输入数组A * 问题描述: 将数组A中奇数放进数组B中,将偶数放进数组C中. * 程序输出:输出数组B与C * 问题分析:略 * 算法设计:略 */ #include<iostream> using namespace std; int main() { const int N=10; int A[N],B[N],C[N],

剑指offer21----数组中奇数偶数

题目描述: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 基本实现 如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有的数字往前面挪动一位.挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位.由于没碰到一个偶数就需要移动O(n)个数字,因此总的时间复杂度是O(n2).但是,这种方法不能让面试官满意.不过如果我们在听到题目之后马上能够说出这个解法,面试官至