【bzoj3751】[NOIP2014]解方程 数论

题目描述

已知多项式方程:

a0+a1*x+a2*x^2+...+an*x^n=0

求这个方程在[1,m]内的整数解(n和m均为正整数)。

输入

第一行包含2个整数n、m,每两个整数之间用一个空格隔开。

接下来的n+1行每行包含一个整数,依次为a0,a1,a2,...,an。

输出

第一行输出方程在[1,m]内的整数解的个数。

接下来每行一个整数,按照从小到大的顺序依次输出方程在[1,m]内的一个整数解。

样例输入

2 10
2
-3
1

样例输出

2
1
2



题解

真心不难的数论题

首先高精度FFT肯定是不可取的,那么就必须取模。但是只有1个模数极有可能多解,所以多选几个大质数模数,如果左边的式子对所有模数取模都为0,则几乎可以判定为原方程的解。

但是这样时间复杂度为$O(nmt)$,其中t是模数个数,会TLE。

我们设$f(i,j)$表示当左面的一坨的x=i时对j取模得到的数,那么显然$f(i,j)=f(i+j,j)=f(i+2j,j)=...$。

所以我们只需要处理0~j-1的数即可,剩下的直接根据前面的推出来。

这样的时间复杂度为$O(t(np+m))$,其中p为模数大小。

所以p不能太大,但是太小也会影响答案正确性,所以取20000左右的质数最合适。

Tip1:bzoj里的1010000指的是1010000,所以a是高精度数(卡在这里无数次qaq)

Tip2:bzoj这道题加强了(加多了)数据,要数据后发现有40个点,但是时间依然是10s,所以常数卡得很死,不能使用long long,模数最好只有3个等等。

#include <cstdio>
#include <cstring>
const int tot = 3;
int prime[3] = {20029 , 22277 , 23333};
int n , m , a[1000010][3] , ok[100010] , cnt[1000010];
char str[1000010];
bool judge(int x , int p)
{
	int i , sum = 0;
	for(i = n ; ~i ; i -- )
		sum = ((sum * x % prime[p] + a[i][p]) % prime[p] + prime[p]) % prime[p];
	return !sum;
}
void read(int c)
{
	scanf("%s" , str);
	int i , j , flag = 1 , l = strlen(str);
	if(str[0] == ‘-‘)
	{
		flag = -1;
		for(i = 0 ; i < l ; i ++ ) str[i] = str[i + 1];
		l -- ;
	}
	for(i = 0 ; i < tot ; i ++ )
	{
		int sum = 0;
		for(j = 0 ; j < l ; j ++ ) sum = (sum * 10 + str[j] - ‘0‘) % prime[i];
		a[c][i] = sum * flag;
	}
}
int main()
{
	int i , j , num = 0;
	scanf("%d%d" , &n , &m);
	for(i = 0 ; i <= n ; i ++ ) read(i);
	for(i = 0 ; i < tot ; i ++ )
	{
		memset(ok , 0 , sizeof(ok));
		for(j = 0 ; j < prime[i] ; j ++ )
			if(judge(j , i))
				ok[j] = 1;
		for(j = 1 ; j <= m ; j ++ ) cnt[j] += ok[j % prime[i]];
	}
	for(i = 1 ; i <= m ; i ++ )
		if(cnt[i] == tot)
			num ++ ;
	printf("%d\n" , num);
	for(i = 1 ; i <= m ; i ++ )
		if(cnt[i] == tot)
			printf("%d\n" , i);
	return 0;
}
时间: 2024-11-05 06:02:55

【bzoj3751】[NOIP2014]解方程 数论的相关文章

BZOJ3751 NOIP2014 解方程(Hash)

题目链接  BZOJ3751 这道题的关键就是选取取模的质数. 我选了4个大概几万的质数,这样刚好不会T 然后统计答案的时候如果对于当前质数,产生了一个解. 那么对于那些对这个质数取模结果为这个数的数也要统计进答案. #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i &g

bzoj3751: [NOIP2014]解方程 数学

题解:http://www.cnblogs.com/mhy12345/p/4109764.html 我也不知道该怎么选质数才比较优越,但是可以用秦九韶算法优化常数,就容易过了. #include<bits/stdc++.h> using namespace std; int f[5]={ 16253,21139,22433,23059,27647 }; int a[5][101]; bool v[5][100000]; char t[10057]; int cnt,st[1000001]; b

【秦九韶算法】【字符串哈希】bzoj3751 [NOIP2014]解方程

在模意义下枚举m进行验证,多设置几个模数,而且小一些,利用f(x+p)%p=f(x)%p降低计算次数.UOJ AC,bzoj OLE. #include<cstdio> #include<iostream> #include<cstring> #include<vector> using namespace std; #define MAXV 4951 vector<int>v; typedef unsigned int ull; const u

BZOJ3751: [NOIP2014]解方程

既然bzoj上有这道题了就把这个坑填了吧... 题解见:http://blog.csdn.net/popoqqq/article/details/40984859 话说这个解法如果当时想到冲突的概率很小的话应该就能想出来233 代码: 1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm>

【BZOJ 3751】 [NOIP2014]解方程

3751: [NOIP2014]解方程 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 914  Solved: 173 [Submit][Status][Discuss] Description 已知多项式方程: a0+a1*x+a2*x^2+...+an*x^n=0 求这个方程在[1,m]内的整数解(n和m均为正整数). Input 第一行包含2个整数n.m,每两个整数之间用一个空格隔开. 接下来的n+1行每行包含一个整数,依次为a0,a1,

luogu2312 解方程 (数论,hash)

luogu2312 解方程 (数论,hash) 第一次外出学习讲过的题目,然后被讲课人的一番话惊呆了. 这个题,我想着当年全国只有十几个满分.....然后他又说了句我考场A这道题时,用了5个模数 确实不好做想不到. 由于\(a\)非常大.转为以下思路. 设 \(f(x) = a_0+a_1x+a_2x^2+\cdots+a_nx^n\) 对于\(f(x) = 0\)则\(f(x)\%p = 0\) \(f(x \% p) = 0\) 然后这里最好是选择素数.由于luogu数据较水,可以直接选择\

NOIP2014解方程

题目:求一个n次整系数方程在1-m内的整数解  n<=100 系数<=10000位 m<=100W 题解:最暴力的想法是枚举x,带入求值看是否为0. 这样涉及到高精度乘高精度,高精度乘单精度,高精度加高精度和高精度减高精度. 复杂度 n*m*len*len ,显然只能过30%的数据 让我们考虑优化: 我们先来研究一下这个算法的主要耗时在哪里 1)将x带入方程左边求值 2)选择多少x带入 我们考虑第一个优化 1)秦九韶算法 只要我们把原方程左边化为 ((An*x+An-1)*x+An-2)

noip2014 解方程(本博文转载于http://blog.csdn.net/popoqqq/article/details/40984859,略有删减)

首先阿贝尔在200年前告诉我们 五次以上方程没有求根公式 于是我们只能枚举1~m 这个是100W 然后100W再加上1W位的精度 都不用运算直接就是跪…… 怎么办呢QAQ 哈希大法好! 令f(x)=an*x^n+...+a1*x^1+a0*x^0 易知若f(x)=0 则f(x) mod p=0 反之如果f(x) mod p=0 那么我们基本可以得出f(x)=0 p比较靠谱的时候碰撞率极低 所以我们把所有的ai都对p取模 然后对于每个解O(n)验证即可 这样是O(m*n)=10 8 (不是一秒么

[BZOJ 3751][NOIP2014]解方程(哈希)

Description 已知多项式方程: a0+a1*x+a2*x^2+...+an*x^n=0 求这个方程在[1,m]内的整数解(n和m均为正整数). Solution 一道很久很久以前就应该做的noip的题 一定要放上来是要见证我人品崩坏的一下午 生无可恋…QAQ 题解其实也很简单啦 随便找几个素数取模验证是不是等于0就好了 随便 随便 随便 随便找几个…素数 在WA\TLE\OLE间切换,最后还是抄了别人的几个素数 怀疑人生[望天 (BZOJ上的数据是加强了的,如果是ccf的数据那当然就随