1. 程式人生 > >[Noip2014] 解方程

[Noip2014] 解方程

lld strong 輸入輸出格式 輸出 沖突 lang ems art sizeof

題目描述

已知多項式方程: $$a_0+a_1x+a_2x^2+\cdots+a_nx^n=0$$

求這個方程在 $[1,m]$ 內的整數解( $n$ 和 $m$ 均為正整數)。


輸入輸出格式

輸入格式:

輸入共 $n + 2$ 行。

第一行包含 $2$ 個整數 $n, m$ ,每兩個整數之間用一個空格隔開。

接下來的 $n+1$ 行每行包含一個整數,依次為 $a_0,a_1,a_2\ldots a_n$ 。

輸出格式:

第一行輸出方程在 $[1,m]$ 內的整數解的個數。

接下來每行一個整數,按照從小到大的順序依次輸出方程在 $[1,m]$ 內的一個整數解。


輸入輸出樣例

輸入樣例#1:
2 10 
1
-2
1
輸出樣例#1:
1
1
輸入樣例#2:
2 10
2
-3
1
輸出樣例#2:
2
1
2
輸入樣例#3:
2 10 
1  
3  
2  
 
輸出樣例#3:
0

說明

對於 $30\%$ 的數據: $0<n\le 2,|a_i|\le 100,a_n≠0,m<100$ 。

對於 $50\%$ 的數據: $0<n\le 100,|a_i|\le 10^{100},a_n≠0,m<100$ 。

對於 $70\%$ 的數據: $0<n\le 100,|a_i|\le 10^{10000},a_n≠0,m<10^4$ 。

對於 $100\%$ 的數據: $0<n\le 100,|a_i|\le 10^{10000},a_n≠0,m<10^6$ 。


瘋狂加美元符結果都沒有用好傷心啊。

一看數據範圍就知道這題一般的算法做不出來,這數據範圍高精度過不去...

掙紮了一下午無望然後膜拜題解。

wao!這太神了。

這題要我在考場上絕對想不出來。

誰腦洞這麽大想出取模的方法啊233了。

先把輸入的$\large ai$對一個素數取模然後用秦九韶算。

我們設原函數為$\large f[]$。

那麽$\large f[x]%p=0%p=0$。

所以取一個素數當模數就行了。

然而50分。

因為以上的算法沖突的概率是很大的, 解決方法就是多取幾個模數。

然後70,剩下的TLE。

如何解決?

我們考慮,$\large f[x]%p!=0, f[x*k+b]%k!=0$.

所以我們只需要求出1~mod-1的答案就行了。


#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
using namespace std;
#define reg register
#define ll long long
#define int long long

int n, m;
int a[105][3];
bool can[1000004][3];
int p[3] = {23333, 23537, 15733};
char ch[10005];
int ans[1000005], cnt;

signed main()
{
    scanf("%lld%lld", &n, &m);
    for (reg int i = 0 ; i <= n ; i ++)
    {
        memset(ch, 0, sizeof ch);
        scanf("%s", ch + 1);
        int len = strlen(ch + 1);
        int tmp[3] = {0}, fu = 1;
        int j = 1;
        if (ch[1] == -) fu = -1, j = 2;
        for (j ; j <= len ; j ++)
            for (reg int k = 0 ; k <= 2 ; k ++)
                tmp[k] = (tmp[k] * 10 + ch[j] - 0) % p[k];
        for (reg int k = 0 ; k <= 2 ; k ++)
        {
            a[i][k] = tmp[k];
            if (fu == -1) a[i][k] = p[k] - a[i][k];
        }
    }
    for (reg int i = 0 ; i <= mod ; i ++)
    {
        for (reg int k = 0 ; k <= 2 ; k ++)
        {
            ll sum = a[n][k];
            for (reg int j = n - 1 ; j >= 0 ; j --)
                sum = ((a[j][k] + sum * i) % p[k] + p[k]) % p[k];    
            if (!sum) can[i][k] = 1;
        }
    }
    for (reg int i = 1 ; i <= m ; i ++)
    {
        for (reg int k = 0 ; k <= 2 ; k ++)
            if (!can[i%p[k]][k])  goto End;
        ans[++cnt] = i;
        End:;
    }
    printf("%lld\n", cnt);
    for (reg int i = 1 ; i <= cnt ; i ++)
        printf("%lld\n", ans[i]);
    return 0;
}

[Noip2014] 解方程