Vijos P1915 解方程 加强版 还是Hash大法好!

题目大意:同解方程 数据范围m<=10^8

O(m)做法见 http://blog.csdn.net/popoqqq/article/details/40984859

O(m)跪了你就当我没辙么?

首先找到一个比较靠谱的第一个质数 将对第一个质数取模为0的值全都存在一个数组里

由于这个是有循环节的 所以我们只需要处理出[0,p-1]中对第一个质数取模为0的数就可以搞出所有了

然后对于这个数组里的所有数用剩余的质数验证一遍就行了

时间复杂度未知 但是第一个质数必须靠谱 如果第一个质数被卡掉那就退化成O(m)了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 110
using namespace std;
typedef long long ll;
const int prime[]={30011,11261,14843,19997,10007,21893};
int n,m,stack[1001001],top;
int ans[110],tot;
ll a[M][6],f[30011][6];
inline ll F(int x,int j)
{
    int i;
    ll re=0;
    for(i=n;~i;i--)
        re=(re*x+a[i][j])%prime[j];
    return re;
}
inline void Input(int x)
{
    static char s[10100];
    int i,j;
    bool flag=false;
    scanf("%s",s+1);
    for(i=1;s[i];i++)
    {
        if(s[i]=='-')
            flag=true;
        else
            for(j=0;j<6;j++)
                a[x][j]=( (a[x][j]<<1) + (a[x][j]<<3) + s[i]-'0' )%prime[j];
    }
    if(flag) 
        for(j=0;j<6;j++)
            a[x][j]=prime[j]-a[x][j];
}
int main()
{
	
	//freopen("equation.in","r",stdin);
	
    int i,j;
    cin>>n>>m;
    for(i=0;i<=n;i++)
        Input(i);
     
    for(j=0;j<6;j++)
        for(i=0;i<prime[j];i++)
            f[i][j]=F(i,j);
         
    for(i=0;i<prime[0];i++)
    {
    	if(f[i%prime[0]][0]==0)
            stack[++top]=i;
    }
    
    for(i=1;i<=top;i++)
    {
    	if(stack[i]+prime[0]>m)
    		break;
    	stack[++top]=stack[i]+prime[0];
    }
    
    for(i=1;i<=top;i++)
    {
    	if(stack[i]>m)
    		break;
    	for(j=1;j<6;j++)
    		if(f[stack[i]%prime[j]][j])
    			break;
    	if(j==6)
    		ans[++tot]=stack[i];
    }
    
    cout<<tot<<endl;
    for(i=1;i<=tot;i++)
        printf("%d\n",ans[i]);
}


你可能感兴趣的:(hash,vijos,VijosP1915)