0%

<a name="SECTION00010000000000000000" style="color: rgb(202, 0, 0);">Horner&#39;s Rule for Polynomials</a>

<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">A general polynomial of degree </span>![$n$](http://www.physics.utah.edu/~detar/lessons/c++/array/img1.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> can be written as </span>
![/begin{displaymath} P(x) = a_0 + a_1 x + a_2 x^2 + ... + a_n x^n = /sum_{i=0}^n a_i x^i /end{displaymath}](http://www.physics.utah.edu/~detar/lessons/c++/array/img2.gif) (1)
<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">If we use the Newton-Raphson method for finding roots of the polynomial we need to evaluate both </span>![$P(x)$](http://www.physics.utah.edu/~detar/lessons/c++/array/img3.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> and its derivative </span>![$P^/prime(x)$](http://www.physics.utah.edu/~detar/lessons/c++/array/img4.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> for any </span>![$x$](http://www.physics.utah.edu/~detar/lessons/c++/array/img5.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">.</span>

It is often important to write efficient algorithms to complete a project in a timely manner. So let us try to design the algorithm for evaluating a polynomial so it takes the fewest flops (floating point operations, counting both additions and multiplications). For concreteness, consider the polynomial 
![/begin{displaymath} 7x^3 + 5x^2 - 4x + 2. /end{displaymath}](http://www.physics.utah.edu/~detar/lessons/c++/array/img6.gif)
<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">The most direct evaluation computes each monomial </span>![$a_i x^i$](http://www.physics.utah.edu/~detar/lessons/c++/array/img7.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> one by one. It takes </span>![$i$](http://www.physics.utah.edu/~detar/lessons/c++/array/img8.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> multiplications for each monomial and </span>![$n$](http://www.physics.utah.edu/~detar/lessons/c++/array/img1.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">additions, resulting in </span>![$n(n+3)/2$](http://www.physics.utah.edu/~detar/lessons/c++/array/img9.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> flops for a polynomial of degree </span>![$n$](http://www.physics.utah.edu/~detar/lessons/c++/array/img1.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">. That is, the example polynomial takes three flops for the first term, two for the second, one for the third, and three to add them together, for a total of nine. If we reuse </span>![$x^i$](http://www.physics.utah.edu/~detar/lessons/c++/array/img10.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">from monomial to monomial we can reduce the effort. In the above example, working backwards, we can save </span>![$x^2$](http://www.physics.utah.edu/~detar/lessons/c++/array/img11.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> from the second term and get </span>![$x^3$](http://www.physics.utah.edu/~detar/lessons/c++/array/img12.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> for the first in one multiplication by </span>![$x$](http://www.physics.utah.edu/~detar/lessons/c++/array/img5.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">. This strategy reduces the work to </span>![$3n-1$](http://www.physics.utah.edu/~detar/lessons/c++/array/img13.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> flops overall or eight flops for the example polynomial. For short polynomials, the difference is trivial, but for high degree polynomials it is huge. A still more economical approach regroups and nests the terms as follows: </span>
![/begin{displaymath} 2 - 4x + 5x^2 + 7x^3 = 2 + x[-4 + x(5 + 7x)]. /end{displaymath}](http://www.physics.utah.edu/~detar/lessons/c++/array/img14.gif)
<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">(Check the identity by multiplying it out.) This procedure can be generalized to an arbitrary polynomial. Computation starts with the innermost parentheses using the coefficients of the highest degree monomials and works outward, each time multiplying the previous result by </span>![$x$](http://www.physics.utah.edu/~detar/lessons/c++/array/img5.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;"> and adding the coefficient of the monomial of the next lower degree. Now it takes </span>![$2n$](http://www.physics.utah.edu/~detar/lessons/c++/array/img15.gif)<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">flops or six for the above example. This is the efficient </span>**Horner&#39;s algorithm**<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">.</span>



<span style="color: rgb(0, 0, 0); font-family: Arial; font-size: 14.399999618530273px; line-height: 26px;">还有一个网站:</span>[http://www.wutianqi.com/?p=1426](http://www.wutianqi.com/?p=1426)

网上一堆讲解,基本知道什么样子然后套用模板就行

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/* BGstep HDU 2815
* 求解a^x == c (mod p) 的 0 <= x < c
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;

const int INF = ~0u>>1;
typedef pair <int,int> P;
typedef long long llg;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
const int N = 100003;
struct Baby_step_Giant_step{
struct edge{int key,times;edge*next;}g[N],*ls[N];
int e;

void add(int x,int times){
int hash = x % N;
for (edge*t=ls[hash];t;t=t->next)
if(t->key == x) return ;
g[++e].key = x;
g[e].times = times;
g[e].next = ls[hash];
ls[hash] = &g[e];
}

int In(int x){
int hash = x % N;
for (edge*t=ls[hash];t;t=t->next)
if(t->key == x) return t->times;
return -1;
}

int Power_mod(int a,int b,int mod){
llg t = a, res = 1;
while (b){
if (b&1) res = res * t % mod;
t = t * t % mod;
b >>= 1;
}
return (int)(res);
}

llg exgcd(int a,int b,llg &x,llg &y){
if (b == 0){
x = 1; y = 0; return a;
}
llg g = exgcd(b,a%b,x,y);
llg tx = x,ty = y;
x = ty; y = tx - a/b*ty;
return g;
}

int solve(int a,int c,int p){
if (c >= p) return -1;
int i,j;
int x = 1; int t = 1;
int s = (int)ceil(sqrt((double)p));
int res,cnt = 0;
llg tx,ty,g;
for (int i = 0; i <= 50; i++)
if (Power_mod(a,i,p) == c)
return i;

while ((g=exgcd(a,p,tx,ty)) != 1){
if (c%g) return -1;
c /= g;
p /= g;
x = (llg)(a)/g*x%p;
cnt ++;
}

e = 0;
memset(ls,0,sizeof(ls));
for (i = 0; i < s; i++) add(Power_mod(a,i,p),i);

for (int step = Power_mod(a,s,p),i = cnt; i < p;
i += s,x = (llg)(x) * step % p){
g = exgcd(x,p,tx,ty);
tx = tx * c % p;
if (tx < 0) tx += p;
res = In((int)tx);
if (res == -1) continue;
return res + i;
}
return -1;
}
}Number_Theory;

int main(){
int a,p,c;
while(~scanf("%d%d%d", &a, &p, &c)){
int ans = Number_Theory.solve(a,c,p);
if (ans == -1) puts("Orz,I can&rsquo;t find D!");
else printf("%dn", ans);
}
return 0;
}

先放着,以后解决单纯形法的优化问题

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#include <cstdio>
#include <cmath>
/**
Simplex C(n+m)(n)
maximize:
c[1]*x[1]+c[2]*x[2]+...+c[n]*x[n]=ans
subject to
a[1,1]*x[1]+a[1,2]*x[2]+...a[1,n]*x[n] <= rhs[1]
a[2,1]*x[1]+a[2,2]*x[2]+...a[2,n]*x[n] <= rhs[2]
......
a[m,1]*x[1]+a[m,2]*x[2]+...a[m,n]*x[n] <= rhs[m]
限制:
传入的矩阵必须是标准形式的, 即目标函数要最大化;
约束不等式均为<= ;xi为非负数(>=0).
simplex返回参数:
OPTIMAL 有唯一最优解
UNBOUNDED 最优值无边界
FEASIBLE 有可行解
INFEASIBLE 无解
n为元素个数,m为约束个数
线性规划:
max c[]*x;
a[][]<=rhs[];
ans即为结果,x[]为一组解(最优解or可行解)
**/
const double eps = 1e-8;
const double inf = 0x3f3f3f3f;

#define OPTIMAL -1 //表示有唯一的最优基本可行解
#define UNBOUNDED -2 //表示目标函数的最大值无边界
#define FEASIBLE -3 //表示有可行解
#define INFEASIBLE -4 //表示无解
#define PIVOT_OK 1 //还可以松弛
#define maxn 1000

struct LinearProgramming{
int basic[maxn], row[maxn], col[maxn];
double c0[maxn];

double dcmp(double x){
if (x > eps) return 1;
else if (x < -eps) return -1;
return 0;
}
void init(int n, int m, double c[], double a[maxn][maxn], double rhs[], double &ans) { //初始化
for(int i = 0; i <= n+m; i++) {
for(int j = 0; j <= n+m; j++) a[i][j]=0;
basic[i]=0; row[i]=0; col[i]=0;
c[i]=0; rhs[i]=0;
}
ans=0;
}
//转轴操作
int Pivot(int n, int m, double c[], double a[maxn][maxn], double rhs[], int &i, int &j){
double min = inf;
int k = -1;
for (j = 0; j <= n; j ++)
if (!basic[j] && dcmp(c[j]) > 0)
if (k < 0 || dcmp(c[j] - c[k]) > 0) k = j;
j = k;
if (k < 0) return OPTIMAL;
for (k = -1, i = 1; i <= m; i ++) if (dcmp(a[i][j]) > 0)
if (dcmp(rhs[i] / a[i][j] - min) < 0){ min = rhs[i]/a[i][j]; k = i; }
i = k;
if (k < 0) return UNBOUNDED;
else return PIVOT_OK;
}
int PhaseII(int n, int m, double c[], double a[maxn][maxn], double rhs[], double &ans, int PivotIndex){
int i, j, k, l; double tmp;
while(k = Pivot(n, m, c, a, rhs, i, j), k == PIVOT_OK || PivotIndex){
if (PivotIndex){ i = PivotIndex; j = PivotIndex = 0; }
basic[row[i]] = 0; col[row[i]] = 0; basic[j] = 1; col[j] = i; row[i] = j;
tmp = a[i][j];
for (k = 0; k <= n; k ++) a[i][k] /= tmp;
rhs[i] /= tmp;
for (k = 1; k <= m; k ++)
if (k != i && dcmp(a[k][j])){
tmp = -a[k][j];
for (l = 0; l <= n; l ++) a[k][l] += tmp*a[i][l];
rhs[k] += tmp*rhs[i];
}
tmp = -c[j];
for (l = 0; l <= n; l ++) c[l] += a[i][l]*tmp;
ans -= tmp * rhs[i];
}
return k;
}
int PhaseI(int n, int m, double c[], double a[maxn][maxn], double rhs[], double &ans){
int i, j, k = -1;
double tmp, min = 0, ans0 = 0;
for (i = 1; i <= m; i ++)
if (dcmp(rhs[i]-min) < 0){min = rhs[i]; k = i;}
if (k < 0) return FEASIBLE;
for (i = 1; i <= m; i ++) a[i][0] = -1;
for (j = 1; j <= n; j ++) c0[j] = 0;
c0[0] = -1;
PhaseII(n, m, c0, a, rhs, ans0, k);
if (dcmp(ans0) < 0) return INFEASIBLE;
for (i = 1; i <= m; i ++) a[i][0] = 0;
for (j = 1; j <= n; j ++)
if (dcmp(c[j]) && basic[j]){
tmp = c[j];
ans += rhs[col[j]] * tmp;
for (i = 0; i <= n; i ++) c[i] -= tmp*a[col[j]][i];
}
return FEASIBLE;
}
//standard form
//n:原变量个数 m:原约束条件个数
//c:目标函数系数向量-[1~n],c[0] = 0;
//a:约束条件系数矩阵-[1~m][1~n] rhs:约束条件不等式右边常数列向量-[1~m]
//ans:最优值 x:最优解||可行解向量-[1~n]
int simplex(int n, int m, double c[], double a[maxn][maxn], double rhs[], double &ans, double x[]){
int i, j, k;
//标准形式变松弛形式
for (i = 1; i <= m; i ++){
for (j = n+1; j <= n+m; j ++) a[i][j] = 0;
a[i][n+i] = 1; a[i][0] = 0;
row[i] = n+i; col[n+i] = i;
}
k = PhaseI(n+m, m, c, a, rhs, ans);
if (k == INFEASIBLE) return k;
k = PhaseII(n+m, m, c, a, rhs, ans, 0);
for (j = 0; j <= n+m; j ++) x[j] = 0;
for (i = 1; i <= m; i ++) x[row[i]] = rhs[i];
return k;
}
}ps; //Primal Simplex

int n,m;
double c[maxn], ans, a[maxn][maxn], rhs[maxn], x[maxn];

int main(){
while(scanf("%d %d", &n, &m) != EOF){
double ans;
ps.init(n, m, c, a, rhs, ans);
for (int i = 1; i <= n; i ++)
scanf("%lf", &c[i]);
for (int i = 1; i <= m; i ++){
for (int j = 1; j <= n; j ++){
scanf("%lf", &a[i][j]);
}
scanf("%lf", &rhs[i]);
}
int hehe=ps.simplex(n,m,c,a,rhs,ans,x);
printf("Nasa can spend %.0f taka.n", ceil(m*ans));
}
return 0;
}

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
/* POJ 2184 DP 背包 
* 在于有负数的情况,平移可以解决,平移100000,这样原来的0就是现在的100000
* 在一般的01背包压缩空间的时候,体积的遍历是从大到小,
* 因为dp[v]=max(dp[v],dp[v-c[i]]+w[i]),
* 当前的dp[v]只取决于比自己小的dp[v-c[i]],
* 所以从大到小遍历时每次dp[v-c[i]]和dp[v]都是上一次的状态。
* 如果体积为负v-c[i]>v,从大到小遍历dp[v-c[i]]是当前物品的状态,
* 不是上一个,这样就会出错,解决的办法是从小到大遍历。
*
* 还有边界的部分不需要怎么考虑因为,数据比较小,
* 按理不会出现达到-100000还能变到不是负数的情况所以你的dp[0]或者dp[p[i].s]
* 开始没有多少区别
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
#include <climits>
using namespace std;

const int INF = ~0u>>1;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
const int maxn = 100005;
int dp[maxn * 2];
int n;
struct node{
int s,f;
}p[200];
int main(){
while (~scanf("%d", &n)){
for (int i = 0; i < 2 * maxn; i++)
dp[i] = INT_MIN;
for (int i = 0; i < n; i++)
scanf("%d%d", &p[i].s, &p[i].f);
dp[100000] = 0;
for (int i = 0; i < n; i++){
if(p[i].s >= 0){
for (int j = 2 * maxn - 1; j >= p[i].s; j--){
if (dp[j-p[i].s] > INT_MIN)
dp[j] = max(dp[j],dp[j-p[i].s]+p[i].f);
}
}else {
for (int j = 0; j - p[i].s <= 200000; j++){
if (dp[j-p[i].s] > INT_MIN)
dp[j] = max(dp[j],dp[j-p[i].s]+p[i].f);
}
}
}
int ans = 0;
for (int i = 100000; i < 2 * maxn; i++)
if(dp[i] >= 0) // 注意f要>=0按照题意
ans = max(ans,dp[i]+i-100000);
printf("%dn", ans);
}
return 0;
}

简单的最短路应用,只是把修改dist数组或者dp数组的条件改变一下就行

还有Map的查找

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
/*
*
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <map>
#include <vector>
using namespace std;

const int INF = 10020000;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
#define maxn 220
int n,m,num;
map<string,int>maps;
int edge[maxn][maxn];
int query(string s)
{
map<string,int>::iterator it;
it = maps.find(s);
if (it == maps.end()){
maps[s] = num++;
return maps[s];
}else return maps[s];
}

void floyd()
{
for (int k = 1; k <= n; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
{
edge[i][j] = max(edge[i][j],min(edge[i][k],edge[k][j]));
}
}

int main(){
int co = 0,w;
char s1[100],s2[100];
while (scanf("%d%d", &n, &m) && (m + n)){
getchar();
num = 1;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; j++)
edge[i][j] = 0;
for (int i = 1; i <= m; ++i)
{
scanf("%s%s%d", s1, s2, &w);getchar();
int x = query(s1);
int y = query(s2);
edge[x][y] = w;
edge[y][x] = w;
}
floyd();
scanf("%s%s",s1,s2);
int x = query(s1);
int y = query(s2);
printf("Scenario #%dn%d tonsnn", ++co, edge[x][y]);
}
return 0;
}

1
2
3
4
5
6
7
8
9
10
//首先求末尾零的个数的求法,就是求5的因子的个数,因为2&times;5得到一个0.
//这个函数函数求1-N因子个数的求法
int cali(int n,int i){
int ret = 0;
while(n){
n /= i;
ret += n;
}
return ret;
}

当i=5时,就可以用来求:N!的末尾的零的个数。

问题是求关于N!的最后一位非0位, 如3!=6,最后一位非0位为6, 5!=120, 最后一位非0位为2.怎么样快速的求出最后一位非0位呢?

最朴素的想法就是先求出N!的结果,再求出结果的最后一位非0位.当N比较小时,是可以承受的,但是当N达到一定规模的时候,时间,空间都不会太理想.这里需要一些技巧.既然是求最后一位非0位,我们就可以先除非所有对结果没有影响的数,如10的倍数.于是先把N!因子分解得到形如2^a5^bc.这个时候我们去掉一个b个5因子和b个2因子,最后一位非0位是不变的.(N!中2的因子一定不会比5的因子少).于是我们的要求的结果就变为(2^(a-b)c)%10.由(ab)%10=((a%10)(b%10))%10我们可以得((2^(a-b)%10)(c%10))%10,由于c不会产生未位为0,故只保留c的最未位即可.于是可将c转化为1,3,7,9因子的相乘得到的结果的最未位(因为1,3,7,9因子相乘不会产生最未非0位,故去掉高位不会对结果产生影响,同时1*n=n可以去掉1的因子).

2,3,7,9因子规律如下:

 2^1=2, 2^2=4, 2^3=8, 2^4=16->(6), 2^5=32->(2)

3^0=1, 3^1=3, 3^2=9, 3^3=27->(7), 3^4=81->(1)

7^0=1, 7^1=7, 7^2=49->(9), 7^3=343->(3), 7^4=2401->(1)

9^0=1, 9^1=9, 9^2=81->(1), 9^3=729->(9), 9^4=6561->(1)

它们都是以4为循环周期的.于是我们只要求出2, 5, 3, 7, 9因子的个数即可.

首先我们求2,5因子在N!中的个数.2的因子的每个偶数到少有1个,同时将数列中每个数/2,其中的偶数还有一个2因子.直至n=1或n=0结束.5因子求法相同.代码直接调用cali(2)和cali(5)就行

3,7,9因子的个数有多少呢?对于1,2,3,4……n-1,n来说,未尾以3,7,9结束的数的个数为n/10+(n%10³f?1:0),(f=3,7, 9).同时我们对于对于奇数数列/5可以得到一个新的数列也有3,7,9因子,对于偶数数列/2也可以得到新的数列也有3,7,9的因子,将所有的3,7,9因子相加即可得到总的3,7,9因子的个数.得到3,7,9因子的个数后,我们可以将其全部转化为因子3的个数.因为9=33(3^2), 7=(333(3^3))%10,设f3, f7, f9为3, 7, 9因子的个数,全部转化为因子3的个数为f3+2f9+3*f7.

于是我们可以用递归同时求2,3,5,7,9因子的个数,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
void solve(int n){
if(n<=1) return ;
for (int i = n; i > 0; i /= 5){
int p = i/10,q = i%10;
co3 += p + (int)(q>=3);
co5 += p + (int)(q>=5);
co7 += p + (int)(q>=7);
co9 += p + (int)(q>=9);
}
co2 += n/2;
solve(n/2);
}

然后N!末尾零便是:

ans[n] = (1*pmod(2,co2-co5)*pmod(3,co3)*pmod(7,co7)*pmod(9,co9))%10;

pmod函数:

1
2
3
4
5
6
7
8
9
inline int pmod(int n,int k){
int ret = 1;
while (k){
if (k&1) ret = ret * n % 10;
n = n * n %10;
k >>= 1;
}
return ret;
}

例题:POJ 1604

其实通过N!的最未非0位的方法我们可以求排列组合数NPM,C(N,M)的最未非0位,用上面的各因子个数减去下面的各因子个数就是结果的各因子个数.只是此时需要注意的是5的因子可能会比2的因子多.当5的因子比2的因子多时,未位一定为5.其余情况与上面相同.

例题:POJ3406和POJ1150

列举一下借的书,和看的书吧:(本学期)

题名 责任者
[国际大学生程序设计竞赛中山大学内部选拔真题解.一](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000532964) 郭嵩山 ... [等] 著
[数值分析导论](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000424419) (美) Kendall Atkinson, 韩渭敏著
[程序员2012精华本](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000541043) 《程序员》杂志社编
[计算几何:算法与应用:algorithms and applications](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000266390) M.de Berg[等]著
[线性代数学习与考研指导](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000415250) 董福安主编
[ACM国际大学生程序设计竞赛:题目与解读](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000536216) 俞勇主编
[MySQL高效编程](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000498978) 王志刚, 江友华编著
[Apache服务器配置与使用工作笔记](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000506763) 王江伟编著
[SGI STL源码剖析:向专家学习型别技术、内存管理、算法、数据结构、STL各类组件之高阶实现技巧](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000490551) 侯捷
[Imperfect C++中文版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000514281) (美) Matthew Wilson著
[电路与电子学基础](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000509468) 周树南, 张伯颐编著
[线性代数复习与考研辅导](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000270151) 吴明鑫,穆瑞金,杨战民编著
[MySQL核心内幕](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000431409) 祝定泽, 张海, 黄健昌编著
[LAMP从入门到精通](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000305420) 张建华主编
[大学物理教学指导与精选题解](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000242379) 倪德渊, 刘映栋, 陆正兴编著
[Metasploit渗透测试指南](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000498888) (美) David Kennedy ... [等] 著
[BackTrack 4:利用渗透测试保证系统安全:assuring security by penetration testing](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000498127) (英) Shakeel Ali, Tedi Heriyanto著
[Linux指令范例查询宝典](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000516432) 郝朝阳, 管文蔚编著
[Linux Shell脚本攻略](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000518797) (印) Sarath Lakshman著
[计算机算法与程序设计实践](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000445733) 董东, 周丙寅编著
[组合数学](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000508969) (美) Richard A. Brualdi著
[图论导引](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000348738) (美) Gary Chartrand,Ping Zhang著
[数学聊斋](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000407313) 王树和著
[你亦可以造幻方](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000508477) 詹森著
[大学英语四六级考试词汇高分突破](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000447091) 黄磊, 王丽主编
[Linux命令行与shell脚本编程大全](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000516469) (美) Richard Blum, Christine Bresnahan著
[Python编程入门经典](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000486962) (美) James Payne著
[捉虫日记](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000516485) (德) Tobias Klein著
[线性代数全程导学及习题全解](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000277739) 周冬梅, 杨莉主编
[线性代数应该这样学](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000415675) (美) Sheldon Axler著
[自然哲学的数学原理:与《相对论》一样,开创了科学的全新纪元.修订版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000488417) (英) 艾萨克·牛顿著
[Linux命令、编辑器与Shell编程](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000508911) 王刚编著
[独唱团.第1辑](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000517080) 韩寒著
[《时代》周刊精选阅读与词汇精通.影印版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000499037) (美) Linda Schinke-Liano编著
[思考的技术:思考力决定领导力](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000350632) (美)约翰·N. 曼吉埃里(John N. Mangieri),(美)凯茜·柯林斯·布劳克(Cathy Collins Block)著
[乌合之众:大众心理研究](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000515613) (法) 古斯塔夫·勒庞著
[线性代数](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000454955) (美) Steven J. Leon著
[由浅入深学PHP:基础、进阶与必做300题](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000479640) 陈向辉等编著
[经典密码学与现代密码学](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000255882) (美)Richard Spillman著
[密码学:加密演算法](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000280812) 邓安文编著
[国际大学生程序设计竞赛例题解.一,数论、计算几何、搜索算法专集](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000286673) 郭嵩山 ... [等] 编著
[密码学与网络安全](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000403768) Atul Kahate著
[入侵的艺术](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000320507) (美) Kevin D. Mitnick, William L. Simon译
[计算数论](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000396705) 颜松远著
[同余理论](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000514559) 南秀全, 刘汉文编著
[编程算法新手自学手册](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000518407) 管西京等编著
[ACM程序设计.第2版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000471061) 曾棕根编著
[程序员2012精华本](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000541043) 《程序员》杂志社编
[计算几何:算法与应用:algorithms and applications](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000266390) M.de Berg[等]著
[ACM国际大学生程序设计竞赛.算法与实现](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000538480) 俞勇主编
[算法分析与设计](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000297422) (美) Michael T. Goodrich, Roberto Tamassia著
[图论导引](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000348738) (美) Gary Chartrand,Ping Zhang著
[MATLAB数字图像处理.第2版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000501490) 张德丰等编著
[MATLAB科学计算宝典](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000510997) 刘正君编著
[编写高质量代码.改善C++程序的150个建议.150 suggestions to improve your C++ program](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000497193) 李健著
[PHP、MySQL和Apache入门经典](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000540839) (美) Julie C. Meloni著
[ACM国际大学生程序设计竞赛知识与入门](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000536628) 俞勇主编
[ACM程序设计.第2版](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000471061) 曾棕根编著
[软件加密与解密:obfuscation, watermarketing, and tamperproofing for software protection](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000507975) (美) Christian Collberg, Jasvir Nagra著
[线性代数](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000323799) (美) Steven J. Leon著
[博弈论精粹](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000399519) 刘培杰执行主编
[Linux/Unix设计思想](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000504317) (美) Mike Gancarz著
[可爱的Python](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000436868) 哲思社区著
[BIOS与注册表](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000483930) 九州书源编著
[编码:隐匿在计算机软硬件背后的语言:the hidden language of computer hardware and software](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000445606) (美) Charles Petzold著
[ACM图灵奖演讲集:前20年 (1966-1985):the first twenty years, 1966-1985](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000241062) (美) Robert L. Ashenhurst, (美) Susan Graham著
[数学拼盘和斐波那契魔方](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000458717) 冯贝叶编著
[计算机算法与程序设计实践](http://202.119.83.14:8080/uopac/opac/item.php?marc_no=0000445733) 董东, 周丙寅编著

有一些是借过两遍的所以会不显示。

然后自己买的一些书:

高观点下的初等数学

Java编程思想

ACM国际大学程序设计竞赛:题目与解读

谣言粉碎机

卡夫卡中短篇小说集

我不是教你诈

奇点临近

Godel Escher Bach (一般称为GEB)

纳什均衡博弈论

算法艺术与信息学竞赛(传说中的黑书)

TCP/IP详解(卷1:协议)

编译原理

计算几何-算法设计与分析

云计算与分布式系统:从并行处理到物联网

深入理解计算机系统

什么是数学(这本书很好)

图论算法理论,实现与应用

看见

树状数组是一种非常优雅的数据结构.
当要频繁的对数组元素进行修改,同时又要频繁的查询数组内任一区间元素之和的时候,可以考虑使用树状数组.
最直接的算法可以在O(1)时间内完成一次修改,但是需要O(n)时间来进行一次查询.
而树状数组的修改和查询均可在O(log(n))的时间内完成.
对于维护的序列`A`,定义`C[i]=A[j+1]+...+A[i]`,其中`j`为`i`的二进制表示中把最右边的1换成0的值。`j`的值可以通过`lowbit`求出,即
j = i - lowbit(i);
`lowbit(a)`为`2^(a的二进制表示末尾0的个数)`。可以用下面式子求出
lowbit(a)=a&(~a+1)
或者根据补码的性质简化为
lowbit(a)=a&(-a)
lowbit函数
inline int lowbit(int x)
{
    return x & (-x);
}
修改方式如下
void modify(int p,int delta){
    while (p<=n){//n的含义要记得,原数组的下标是1~n
        c[p] += delta;
        p += lowbit(p);
    }
}
求前缀和如下
int sum(int p){
    int ret = 0;
    while (p){
        res += c[p];
        p -= lowbit(p);    
    }
    return ret;
}
* * * 树状数组求解区间最大值的时候,需要按照一定的顺序进行求解,把前面的区间后加上去就可以求。 然后树状数组求解逆序对的时候,就是求对i,之前比它大的数有几个,树状数组里面存的是数字有没有在数组里面出现,这样就能求逆序。 求一个数排第几也是同样的想法,有就置为1,没有这个位置就是0。 * * *
树状数组可以解决更新线段区间,查询某个点的问题。 在这种情况下,更新线段区间和查询点的时间复杂度仍然为O(logn). 设A[1,N]为我们要处理的数组。 另外设置一个数组B[1,N],使得B[1] + B[2] + .. B[i] = A[i], 其中1 <= i <= N.即B[i] = A[i] - A[i-1]
    <span style="color: rgb(0, 0, 0); font-family: Verdana, tahoma, Arial, Helvetica, sans-serif; font-size: 14px; line-height: 21px;">当要查询A[i]的时候,我们只需在数组B上使用一般的树状数组操作查询区间[1,i]即可</span>

    <span style="font-family: Verdana, tahoma, Arial, Helvetica, sans-serif;">当我们要给区间A[a~b]加上delta时,只需要在数组B上对B[a]进行一般树状数组的更新delta的操作,同时对数组B上对B[b+1]进行 - delta操作。</span>

    树状数组可被扩展到多维的情况。假设在一个布满点的平面上(坐标是非负的)。 你有以下三种查询:
  1. 将点(x, y)置1
  2. 将点(x, y)置0
  3. 计算左下角为(0, 0)右上角为(x, y)的矩形内有多少个点(即有多少个1)

    C[x][y] = ∑ a[i][j], 其中, x-lowbit(x) + 1 <= i <= x, y-lowbit(y) + 1 <= j <= y.
    在二维情况下,对应的更新和查询函数为:
    
    <div style="word-break: break-all;">
        <pre class="brush:cpp">

void Modify(int x, int y, int delta)
{
for(int i = x; i <= N; i += lowbit(i))
for(int j = y; j <= N; j += lowbit(i))
C[x][y] += delta;
}</pre>

        <pre class="brush:cpp">

int Sum(int i, int j)
{
int ret = 0;
for(int x = i; x > 0; x -= lowerbit(x))
{
for(int y = j; y > 0; y -= lowerbit(y))
{
ret += C[x][y];
}
}
return ret;
}</pre>

    </div>









</div>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2; font-size: large;">总结</span>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: 14px; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">BIT很容易编码实现</span>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: 14px; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">所有的查询均花费logn或者常数时间</span>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: 14px; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">需要线性数量级的空间</span>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: 14px; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">可以扩展到n维的情况,BIT可以作为一种多维的数据结构,即可扩展到多维。以上只是一维二维的情况。</span>

    <span style="font-size:16px;">扩展阅读</span>

    <span style="color: rgb(0, 0, 0); font-family: 微软雅黑; font-size: 14px; line-height: normal; orphans: 2; text-align: -webkit-auto; widows: 2;">翻译自TopCoder上的一篇文章: </span>[Binary Indexed Trees](http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees) :[http://hawstein.com/posts/binary-indexed-trees.html](http://hawstein.com/posts/binary-indexed-trees.html) 

    比较详细的树状数组介绍 :[http://duanple.blog.163.com/blog/static/7097176720081131113145832/](http://duanple.blog.163.com/blog/static/7097176720081131113145832/)

    二维树状数组 : [http://old.blog.edu.cn/user3/Newpoo/archives/2007/1712628.shtml](http://old.blog.edu.cn/user3/Newpoo/archives/2007/1712628.shtml)

</div>

独立集:

 独立集是指图的顶点集的一个子集,该子集的导出子图不含边.如果一个独立集不是任何一个独立集的子集, 那么称这个独立集是一个极大独立集.一个图中包含顶点数目最多的独立集称为最大独立集。最大独立集一定是极大独立集,但是极大独立集不一定是最大的独立集。

**支配集:**

     与独立集相对应的就是支配集,支配集也是图顶点集的一个子集,设S 是图G 的一个支配集,则对于图中的任意一个顶点u,要么属于集合s, 要么与s 中的顶点相邻。 在s中除去任何元素后s不再是支配集,则支配集s是极小支配集。称G的所有支配集中顶点个数最 少的支配集为最小支配集,最小支配集中的顶点个数成为支配数。

**最小点的覆盖:**

     最小点的覆盖也是图的顶点集的一个子集,如果我们选中一个点,则称这个点将以他为端点的所有边都覆盖了。将图中所有的边都覆盖所用顶点数最少,这个集合就是最小的点的覆盖。

**最大团:**

     图G的顶点的子集,设D是最大团,则D中任意两点相邻。若u,v是最大团,则u,v有边相连,其补图u,v没有边相连,所以图G的最大团=其补图的最大独立集。

一些性质:

最大独立集+最小覆盖集=V

最小覆盖集>=最大匹配(二分图时等号成立)

最大团=补图的最大独立集 

**最大匹配问题:**

 给定一个二分图G,在G的一个子图M中,M的边集中的任意两条边都不依附于同一个顶点,则称M是一个匹配。 

 选择这样的边数最大的子集称为图的最大匹配问题(maximal matching problem) 

 求二分图最大匹配可以用最大流或者匈牙利算法。

**完备匹配:**

 如果一个匹配中,图中的每个顶点都和图中某条边相关联,则称此匹配为完全匹配,也称作完备匹配。 

** 

完全图:**

完全图G就是指图G的每个顶点之间都有连边。

这样,令完全图G的阶|G|=N,那么完全图G具有如下性质:

1.图G有(N-1)*N/2条边。

2.图G上的生成树有N^(N-2)种。

3.图G的补图G&#39;中没有边。

定理:一个图T的一个完全子图G,对应它的补图T&#39;上的一个独立集。

那么求一个图的最大完美子图(最大图)就等价于它的补图的最大独立集所包含的点的个数。

**最小路径覆盖:** 

 在一个N*N的有向图中,路径覆盖就是在图中找一些路经,使之覆盖了图中的所有顶点,

 且任何一个顶点有且只有一条路径与之关联;(如果把这些路径中的每条路径从它的起始点走到它的终点,

 那么恰好可以经过图中的每个顶点一次且仅一次);如果不考虑图中存在回路,那么每每条路径就是一个弱连通子集.

 最小路径覆盖就是找出最小的路径条数,使之成为G的一个路径覆盖.

 路径覆盖与二分图匹配的关系:有向图最小路径覆盖=|V| - 最大匹配数; 无向图最小路径覆盖=|V| - 最大匹配数/2。

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
/* floyd + 字符串变数字 
* 看input的里面就行了
* 题意就是求第一个点到各个点最短路径中的最大值。
* 学到直接把字符串改为整型,长整型:
* atof() 将字符串转换成浮点数值
* atoi() 将字符串转换成整数值
* atol() 将字符串转换成长整数值;
* strtod() 将字符串转换成双精度型数值
* strtol() 将字符串转换成长型数值
* 注意把g[i][i] 作为inf虽然应该是0,但floyd进行dp的时候用inf不影响结果但是
* 会少做很多次
* */
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <vector>
using namespace std;
const int INF = ~0u>>1;
typedef pair <int,int> P;
#define MID(x,y) ((x+y)>>1)
#define iabs(x) ((x)>0?(x):-(x))
#define REP(i,a,b) for(int i=(a);i<(b);i++)
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define pb push_back
#define mp make_pair
#define print() cout<<"--------"<<endl
#define maxn 105

int n, g[maxn][maxn];
void floyd(){
FOR(k,1,n)
FOR(i,1,n)
FOR(j,1,n)
if(g[i][k] != INF && g[k][j] != INF){
g[i][j] = min(g[i][j],g[i][k]+g[k][j]);
}
}

int main(){
char s[10];
scanf("%d", &n);
getchar();
FOR(i,1,n) g[i][i] = INF;//用inf更加快,0会慢一点
FOR(i,2,n)
FOR(j,1,i-1){
scanf("%s", s);
if (s[0] == 'x') g[i][j] = g[j][i] = INF;
else {
g[i][j] = atoi(s);
g[j][i] = g[i][j];
}
}
floyd();
int ans = 0;
FOR(i,1,n) ans = max(ans,g[1][i]);
printf("%dn", ans);
return 0;
}