NOIP2014 解方程 解题报告(取模运算+秦九韶定理)

在线评测:

http://codevs.cn/problem/3732/

整体思路:

我们看一下数据,一言不合就上10000次方,显然高精度也是不合适的,显然在把我们向非完美算法引导,所以我们想一下,这种情况下你不取模还干啥,所以果断把系数高精度取模一个素数,然后我们来想一下,然后呢,我们考虑一下如果我们对于一个方程的系数取模一个数,实际上大多数情况下如果运算符合,他都是正确的,只有当我们算的数是用于取模的几个素数的公倍数的时候才会误判,所以我们可以取3个10^4级别的素数,然后暴力枚举m然后秦九韶就好了,然后我们在算一下复杂度,3 * 10^8次方,还有常数,要GG,所以我们得考虑一下能不能预处理点什么,我们想f(x+mo1) = f(mo1) (在取模 mo1的情况下),所以我们只要预处理出,在选择模第几个质数的情况下,带入1-这个质数 这个数方程预算结果就行了,由于我们取得是10^4级别的素数,所以复杂都就掉成了两个10^6次方,这样子就舒服很多了,然后就可以AC了,,(开始只有90,据说我三个素数取得不优美,据说这概率很小很小。脸黑伤心)

失误之处:

开始我tmd犯了一个一生犯过的最蠢的错,+= 运算符知道吧,-=运算符知道吧,*=,/=都知道吧,然后我tmd把 %=硬生生的写成了 %,没错,没有等于号,,,,然后就一直只过30的超小数据,,满脸蒙蔽,,,

体会心得:

写代码时认真点,,别犯这种这么白痴的错误,,,QAQ

AC代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>
using  namespace  std;
const  int  mo1 = 10111,mo2 = 10133,mo3 = 23333;
int  n,m;
int  sz[4][200];
int  ans[4][2000000],tot;
queue < int > dl;
char  tp[100000];
int  main()
{
     scanf ( "%d%d" ,&n,&m);
     for  ( int  mi = 0; mi <= n; mi++)
     {
         bool  fu =  false ;
         int  itp = 0;
         scanf ( "%s" ,tp);
         int  lenn =  strlen (tp);
         int  jl1 = 0,jl2 = 0,jl3 = 0;
         if  (tp[0] ==  '-'
         {
             fu =  true ;
             itp = 1;
         }
         for  ( int  i = itp; i < lenn; i++)
         {
             jl1 = jl1 * 10 + (tp[i] -  '0' );
             jl1 %= mo1;
             jl2 = jl2 * 10 + (tp[i] -  '0' );
             jl2 %= mo2;
             jl3 = jl3 * 10 + (tp[i] -  '0' );
             jl3 %= mo3;
         }
         sz[1][mi] = jl1;
         sz[2][mi] = jl2;
         sz[3][mi] = jl3;
         if  (fu)
         {
         /*  sz[1][mi] = (sz[1][mi] * (mo1 - 1)) % mo1;
             sz[2][mi] = (sz[2][mi] * (mo2 - 1)) % mo2;
             sz[3][mi] = (sz[3][mi] * (mo3 - 1)) % mo3;
             */
             sz[1][mi] *= -1;
             sz[2][mi] *= -1;
             sz[3][mi] *= -1;
         }
     }
     for  ( int  mi = 1; mi <= 3; mi++)
     {
         for  ( int  i = 0; i <= mo3; i++)
         {
             for  ( int  j = n; j >= 0; j--)
             {
                 ans[mi][i] *= i;
                 if  (mi == 1) ans[mi][i] %= mo1; else
                     if  (mi == 2) ans[mi][i] %= mo2; else
                         if  (mi == 3) ans[mi][i] %= mo3;
                 ans[mi][i] += sz[mi][j];
                 if  (mi == 1) ans[mi][i] %= mo1; else
                     if  (mi == 2) ans[mi][i] %= mo2; else
                         if  (mi == 3) ans[mi][i] %= mo3;
             }
         }
     }
     for  ( int  mi = 1; mi <= m; mi++)
     {
         if  (!(ans[1][mi % mo1]) && !(ans[2][mi % mo2]) && !(ans[3][mi % mo3]))
         {
             tot++;
             dl.push(mi);
         }
     }
     printf ( "%d\n" ,tot);
     while  (!dl.empty())
     {
         printf ( "%d\n" ,dl.front());
         dl.pop();
     }
     return  0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值