NOIP2014 bzoj3751 Day2T3 解方程 数学&hash

这篇博客回顾了NOIP2014的一道竞赛题,讨论了解决此类方程的方法,尤其是利用模运算优化算法。作者指出,通过取模质数可以有效避免输入过大导致的错误,但选择合适质数的数量和大小至关重要,以平衡正确率和运行时间。文中分享了AC代码,并提及CCF数据可能对此类算法的要求较低。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

       NOIP2014的最后一题,本来要在NOIP2015前做好的,现在终于把坑填上了。

       bzoj上的数据似乎经过加强了?质数不取大似乎过不掉。

       真想不明白我初二的时候看到这道题目是怎么在5s内想到去取一个模的(当然不是在考场而是在家里)

       显然,若f(x)=0,则f(x)≡f(x0)≡0(mod p),其中x≡x0(0<=x0<p)。那么如果f(x0)≡0(mod p),那么基本可以确定f(x)=0。当然如果不用p取模的话输入早就爆掉了。。那么如果p比较大的话,比如>m,那么取一个质数,基本上出错概率就很小了。

       但是这么做是无法拿到满分的,而且出错概率也比较大。如果换用若干个较小的质数,比如说10^4级别的,就能满分的。这里我取了7个15000~35000的质数,是程序随机化跑出来的。实测如果去10个10000左右的质数,而且质数比较接近的话会直接OLE(看样子质数太接近会导致出错概率很大),如果取10个又会超时。之所以不往大的取是因为50000*50000>2^31,就要开long long了会减慢速度。然后读入的时候一边读入一边取模就行了。

       似乎并没有什么高科技的东西??感觉只要想到取模就基本上能AC了。

       当然对于ccf那么水的数据,6,7个10000左右质数的似乎就能过去了?

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;

int n,m,a[10][1005],sum[1000005];
char ch[20005];
const int prm[7]={15259,26833,25889,19249,26681,21517,21739};
int main(){
	scanf("%d%d",&n,&m); int i,j,k;
	for (i=0; i<=n; i++){
		scanf("%s",ch+1); int len=strlen(ch+1),p=1;
		if (ch[1]=='-'){ ch[1]='0'; p=-1; }
		for (j=0; j<7; j++){
			for (k=1; k<=len; k++) a[j][i]=(a[j][i]*10+ch[k]-'0')%prm[j];
			a[j][i]=p*a[j][i]%prm[j];
		}
	}
	for (i=0; i<7; i++)
		for (j=0; j<prm[i]; j++){
			int x=a[i][n];
			for (k=n-1; k>=0; k--) x=(x*j+a[i][k])%prm[i];
			if (!x) for (k=j; k<=m; k+=prm[i]) sum[k]++;
		}
	int ans=0; for (i=1; i<=m; i++) if (sum[i]==7) ans++;
	printf("%d\n",ans); for (i=1; i<=m; i++) if (sum[i]==7) printf("%d\n",i);
	return 0;
}

by lych

2015.12.24

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值