刷题记录-P2312 解方程

题目链接:https://www.luogu.org/problem/show?pid=2312

这题一开始是这么考虑的:如果f(x)!=0,那么f(x)%k一定也不等于0
这样可以进行检验,选取若干个k使得解的范围缩小,
最后用高精度一一进行验证。

70分

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 105
#define SIZE 10025
#define MAXM 1000005
#define ll long long
using namespace std;
struct BigInt{
	int len;
	int s[SIZE];
	int p; //p==1 + p==-1 -
	BigInt(){
		p=1;len=0;
		memset(s,0,sizeof(s));
	}
	BigInt operator = (const char A[]){
		int L=strlen(A);
		len=L;
		if('-'==A[0]){
			p=-1; len--;
		}
		else{
			p=1;
		}
		memset(s,0,sizeof(s));
		for(int i=1;i<=len;i++){
			s[i]=A[L-i]-'0';
		}
		return *this;
	}
	BigInt operator = (const BigInt &A){
		len=A.len;
		p=A.p;
		memset(s,0,sizeof(s));
		for(int i=1;i<=len;i++){
			s[i]=A.s[i];
		}
		return *this;
	}
	BigInt operator *= (const int &A){
		for(int i=1;i<=len;i++){
			s[i]*=A;
		}
		for(int i=1;i<=len;i++){
			s[i+1]+=s[i]/10; //+= not +
			s[i]%=10;
		}
		int t=len;
		while(s[t+1]){
			t++;
			s[t+1]+=s[t]/10;
			s[t]%=10;
		}
		len=t;
		return *this;
	}
	// compare Abs
	bool operator < (const BigInt &A){
		if(len!=A.len){
			return (len<A.len);
		}
		for(int i=len;i>=1;i--){
			if(s[i]!=A.s[i]){
				return (s[i]<A.s[i]);
			}
		}
		return 0;
	}
	BigInt operator -= (const BigInt &A){
		BigInt B,C;
		B=*this; C=*this;
		if(B<A){
			B.p=A.p;
			B=A;
		}
		else{
			B.p=p;
			C=A;
		}
		for(int i=1;i<=C.len;i++){
			B.s[i]-=C.s[i];
		}
		for(int i=1;i<=C.len;i++){
			if(B.s[i]<0){
				B.s[i]+=10;
				B.s[i+1]-=1;
			}
		}
		int t=C.len;
		while(B.s[t+1]<0){
			t++;
			B.s[t]+=10;
			B.s[t+1]-=1;
		}
		for(int i=B.len;i>=1;i--){
			if(!B.s[i]){
				B.len--;
			}
			else{
				break;
			}
		}
		if(!B.len) B.len=1;
		return (*this=B);
	}
	BigInt operator += (const BigInt &A){
		if(p*A.p<0){
			return (*this-=A);
		}
		len=max(len,A.len);
		for(int i=1;i<=len;i++){
			s[i]+=A.s[i];
		}
		for(int i=1;i<=len;i++){
			s[i+1]+=s[i]/10;
			s[i]%=10;
		}
		if(s[len+1]){
			len++;
			s[len+1]=s[len]/10;
			s[len]%=10;
		}
		return *this;
	}
	int operator % (const int &A){
		int q=0;
		for(int i=len;i>=1;i--){
			q=q*10+s[i];
			q=q%A;
		}
		return q*p;
	}
	void Print(){
		if(p<0) printf("-");
		for(int i=len;i>=1;i--){
			printf("%d",s[i]);
		}
		printf("\n");
	}
};
BigInt a[MAXN];
int prime[6]={0,1000193,1000367,1000427,1000453};
int n,m;
int b[MAXM];
int B[MAXN];
vector<int> ans,bans;
void read(int k){
	char s[SIZE]={0};
	int len=0;
	char c=getchar();
	do{
		s[len++]=c;
		c=getchar();
	}while('0'<=c&&c<='9');
	a[k]=s;
}
bool check(int k){
	BigInt sum;
	for(int i=n;i>=0;i--){
		sum*=k;
		sum+=a[i];
	}
	if(1==sum.len&&!sum.s[1]){
		return 1;
	}
	return 0;
}
int main()
{
//	freopen("T1.in","r",stdin);
//	freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	getchar();
	for(int i=0;i<=n;i++){
		read(i);
	}
	for(int k=1;k<=4;k++){
		for(int i=0;i<=n;i++){
			B[i]=a[i]%prime[k];
		}
		for(int x=1;x<=m;x++){
			ll sum=0;
			for(int i=n;i>=0;i--){
				sum=((sum*x)+B[i])%(ll)prime[k];
			}
			if(sum){
				b[x]=-1;
			}
			else if(b[x]!=-1){
				b[x]=1;
			}
		}
	}
	for(int i=1;i<=m;i++){
		if(1==b[i]){
			bans.push_back(i);
		}
        }
	for(int i=0;i<bans.size();i++){
		if(check(bans[i])){
			ans.push_back(bans[i]);
	        }
	}
	printf("%d\n",ans.size());
	for(int i=0;i<ans.size();i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}
这题AC解法是利用类似线性筛数的思想,
如果f(x)!=0那么f(x+kMOD)!=0(这个和我的想法是一致的)
关键就在于,我们可以利用这条性质,只处理0~MOD-1的部分
然后对于x,直接对MOD取模,然后就很大程度上减少了计算量
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
#define MAXN 105
#define SIZE 10025
#define MAXM 1000005
#define ll long long
using namespace std;
const int prime[]={10007,10917,30071};
int n,m;
int a[MAXN][4];
bool f[MAXM][4];
char s[SIZE];
vector<int> ans;
bool calc(int x,int j){
	ll sum=0;
	for(int i=n;i>=0;i--){
		sum=(sum*x+a[i][j])%prime[j];
	}
	return (0==sum);
}
int main()
{
//	freopen("T1.in","r",stdin);
//	freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;i++){
		memset(s,0,sizeof(s));
		scanf("%s",s);
		int len=strlen(s),be=0;
		int p=1;
		if('-'==s[0]){
			p=-1;
			be++;
		}
		for(int j=0;j<3;j++){
			ll temp=0;
			for(int k=be;k<len;k++){
				temp=((temp*10)+s[k]-'0')%prime[j];
			}
			a[i][j]=temp*p;
			if(a[i][j]<0) a[i][j]+=prime[j];			
		}
	}
	for(int j=0;j<3;j++){
		for(int i=0;i<prime[j];i++){
			f[i][j]=calc(i,j);
		}
	}
	for(int i=1;i<=m;i++){
		int ok=1;
		for(int j=0;j<3;j++){
			if(!f[i%prime[j]][j]){
				ok=0;
				break;
			}
		}
		if(ok){
			ans.push_back(i);
		}
	}
	printf("%d\n",ans.size());
	for(int i=0;i<ans.size();i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值