目录
Millar Rabin+Pollard rho算法... 9
离散化+01背包 Interview Arrangement. 37
1.转化为分组背包方法 NOIP2006金明的预算方案... 42
poj 3264 Balanced Lineup 最值... 52
数据范围
char -128 ~ +127 (1 Byte)
short -32767 ~ + 32768 (2 Bytes)
unsigned short 0 ~ 65536 (2 Bytes)
int -2147483648~ +2147483647 (4 Bytes)
unsigned int 0 ~4294967295 (4 Bytes)
long == int
long long -9223372036854775808~ +9223372036854775807 (8 Bytes)
double 1.7* 10^308 (8 Bytes)
unsigned int 0~4294967295
unsigned long long的最大值:1844674407370955161
__int64的最大值: 9223372036854775807
__int64的最小值: -9223372036854775808
unsigned __int64的最大值:18446744073709551615
数论
素数
O(n)打表
const int NS=1000100;
int isprime[NS],pri[NS],top=0;
void prime_table()
{
for (int i=2;i<NS;i++)
{
if (!isprime[i]) pri[top++]=i;
for (int j=0;j<top&&i*pri[j]<NS;j++)
{
isprime[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
数量分布 (pi(x)~x/ln(x))
排列组合常见公式
组合恒等式
位数计算
n!最右边非零位
给一个正整数N(N为大整数),输出最右边非零的数字
代码:0//大整数以string的形式传入
int Last_nonzero_Digit_in_N(string str)
{
intmod[20]={1,1,2,6,4,2,2,4,2,8,
4,4,8,4,6,8,8,6,8,2};
int a[1000];
int i, c, t=1,len=str.length();
for (i = 0; i < len;i++)
a[i] = str[len - 1 -i] –‘0’;
while (len)
{
len -= !a[len - 1];
t = t * mod[a[1] % 2 *10 + a[0]] % 10;
for (c = 0, i = len -1; i >= 0; i–)
c = c * 10 + a[i],a[i] = c / 5, c %= 5;
}
return t;
}
Sterling公式
最高位 (int)10^(log10(n)- (int)log10(n))
Millar Rabin+Pollard rho算法
#include<cstdio>
#include<cstdlib>
#include<iostream>
typedef long long LL;
#define MAX((LL)1<<61)
const int CT=201;
const int Times=50;
LL min_factor;
LL multi(LL aa,LL bb,LLmod)
{
LL res=0;
while (bb>0)
{
if (bb&1) res=(res+aa)%mod;
bb>>=1;
aa=(aa<<1)%mod;
}
return res;
}
LL quick_mod(LL aa,LL bb,LLmod)
{
LL res=1;
aa%=mod;
while (bb>0)
{
if (bb&1) res=multi(res,aa,mod);
bb>>=1;
aa=multi(aa,aa,mod);
}
return res;
}
int judge(LL aa,LL n)
{
int c=0;
LL bb=n-1;
while (!(bb&1)) c++,bb>>=1;
LL ans=quick_mod(aa,bb,n);
if (ans==1||ans==(n-1)) return 0;
for (int i=0;i<c;i++)
{
ans=multi(ans,ans,n);
if (ans==n-1) return 0;
}
return 1;
}
int Miller_Rabin(LL n)
{
LL rd;
if (n<2) return 0;
if (n<4) return 1;
if (!(n&1)) return 0;
for (int i=0;i<Times;i++)
{
rd=(LL)((double)rand()/RAND_MAX*(n-2)+2);
if (judge(rd,n)) return 0;
}
return 1;
}
LL gcd (LL aa,LL bb)
{
return bb==0?aa:gcd(bb,aa%bb);
}
LL pollard_rho(LL n,int c)
{
LL d,x,y,i=1,k=2;
y=x=(LL)((double)rand()/RAND_MAX*(n-1)+1);
while (1)
{
i++;
x=(multi(x,x,n)+c)%n;
d=gcd(y-x,n);
if (d>1&&d<n) return d;
if (y==x) return n;
if (i>=k)
{
y=x;
k<<=1;
}
}
}
void Fin(LL n,int c)
{
if (n==1) return ;
if (Miller_Rabin(n))
{
min_factor=n<min_factor?n:min_factor;
return ;
}
LL k=n;
while (k>=n) k=pollard_rho(k,c--);
Fin(k,c);
Fin(n/k,c);
}
int main()
{
int T;
LL n;
scanf("%d",&T);
while (T--)
{
scanf("%I64d",&n);
if (Miller_Rabin(n))
printf("Prime\n");
else
{
min_factor=MAX;
Fin(n,CT);
printf("%I64d\n",min_factor);
}
}
return 0;
}
卡特兰数:
1通项公式:h(n)=C(n,2n)/(n+1)=(2n)!/((n!)*(n+1)!)
2递推公式:h(n)=((4*n-2)/(n+1))*h(n-1); h(n)=h(0)*h(n-1)+h(1)*h(n-2)+...+h(n-1)*h(0).
3前几项为:h(0)=1,h(1)=1,h(2)=2,h(3)=5,h(4)=14,h(5)=42,......
大数类
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int MAXN = 500;
struct bign
{
intlen, s[MAXN];
bign()
{
memset(s,0, sizeof(s));
len= 1;
}
bign(int num) { *this = num; }
bign(const char *num) { *this = num; }
bignoperator = (const int num)
{
chars[MAXN];
sprintf(s,"%d", num);
*this= s;
return*this;
}
bignoperator = (const char *num)
{
for(inti = 0; num[i] == '0'; num++);//去前导0
len= strlen(num);
for(inti = 0; i < len; i++)
s[i] = num[len-i-1] - '0';
return*this;
}
bignoperator + (const bign &b) const //+
{
bignc;
c.len= 0;
for(inti = 0, g = 0; g || i < max(len, b.len); i++)
{
intx = g;
if(i< len) x += s[i];
if(i< b.len) x += b.s[i];
c.s[c.len++]= x % 10;
g= x / 10;
}
returnc;
}
bignoperator += (const bign &b)
{
*this= *this + b;
return*this;
}
voidclean()
{
while(len> 1 && !s[len-1]) len--;
}
bignoperator * (const bign &b) //*
{
bignc;
c.len= len + b.len;
for(inti = 0; i < len; i++)
for(intj = 0; j < b.len; j++)
c.s[i+j]+= s[i] * b.s[j];
for(inti = 0; i < c.len; i++)
{
c.s[i+1]+= c.s[i]/10;
c.s[i]%= 10;
}
c.clean();
returnc;
}
bignoperator *= (const bign &b)
{
*this= *this * b;
return*this;
}
bignoperator - (const bign &b)
{
bignc;
c.len= 0;
for(inti = 0, g = 0; i < len; i++)
{
intx = s[i] - g;
if(i< b.len) x -= b.s[i];
if(x>= 0) g = 0;
else
{
g= 1;
x+= 10;
}
c.s[c.len++]= x;
}
c.clean();
returnc;
}
bignoperator -= (const bign &b)
{
*this= *this - b;
return*this;
}
bignoperator / (const int b)
{
bignc;
intf = 0;
for(inti = len-1; i >= 0; i--)
{
f= f*10+s[i];
c.s[i]=f/b;
f=f%b;
}
c.len= len;
c.clean();
returnc;
}
bignoperator / (const bign &b)
{
bignc, f = 0;
for(inti = len-1; i >= 0; i--)
{
f= f*10;
f.s[0]= s[i];
while(f>= b)
{
f-= b;
c.s[i]++;
}
}
c.len= len;
c.clean();
returnc;
}
bignoperator /= (const bign &b)
{
*this = *this / b;
return*this;
}
bignoperator % (const bign &b)
{
bignr = *this / b;
r= *this - r*b;
returnr;
}
bignoperator %= (const bign &b)
{
*this= *this % b;
return*this;
}
bignoperator ^ (const int & n) //大数的n次方运算
{
bign t(*this),ret(1);
if(n<0) exit(-1);
if(n==0) return 1;
int m=n;
while (m)
{
if (m&1) ret=ret*t;
t=t*t;
m>>=1;
}
return ret;
}
booloperator < (const bign &b)
{
if(len!= b.len) return len < b.len;
for(inti = len-1; i >= 0; i--)
if(s[i]!= b.s[i]) return s[i] < b.s[i];
returnfalse;
}
booloperator > (const bign &b)
{
if(len!= b.len) return len > b.len;
for(inti = len-1; i >= 0; i--)
if(s[i]!= b.s[i]) return s[i] > b.s[i];
returnfalse;
}
booloperator == (const bign &b) {
return!(*this > b) && !(*this < b);
}
booloperator != (const bign &b) {
return!(*this == b);
}
booloperator <= (const bign &b) {
return*this < b || *this == b;
}
booloperator >= (const bign &b) {
return*this > b || *this == b;
}
stringstr() const
{
stringres = "";
for(inti = 0; i < len; i++) res = char(s[i]+'0') + res;
returnres;
}
};
istream& operator >> (istream&in, bign &x)
{
strings;
in>> s;
x= s.c_str();
returnin;
}
ostream& operator << (ostream&out, const bign &x)
{
out<< x.str();
returnout;
}
int main()
{
bigna, b, c, d, e, f, g, h, k;
while(cin>>a>>b)
{
a.clean(),b.clean();
c= a+b, d = a-b;
e= a*b, f = a/b;
g= a%b, h = a/999;
k= a^10;
}
return0;
}
数学公式:
C(m,n)=C(m-1,n)+C(m-1,n-1)
求和公式,k =1..n
1. sum( k^2 ) =n(n+1)(2n+1)/6
2. sum( (2k-1)^2 ) =n(4n^2-1)/3
3. sum( k^3 ) =(n(n+1)/2)^2
4. sum( (2k-1)^3 ) =n^2(2n^2-1)
5. sum( k^4 ) =n(n+1)(2n+1)(3n^2+3n-1)/30
6. sum( k^5 ) =n^2(n+1)^2(2n^2+2n-1)/12
7. sum( k(k+1) ) =n(n+1)(n+2)/3
8. sum( k(k+1)(k+2) ) =n(n+1)(n+2)(n+3)/4
9. sum( k(k+1)(k+2)(k+3) )= n(n+1)(n+2)(n+3)(n+4)/5
10. sum(1/(k^2)) =π^2/6 (n->无穷);
11. sum(k*x^k)=[x-(1+n)x^(n+1)+nx^(n+2)]/(1-x)^2. (x>1);
正整数n的因子之和
n=p1e1p2e2…prer
Sum=(1+p1+p12+…+p1e1)*(1+p2+p22+…+p2e2) *…*(1+pr+pr2+…+prer)
勾股数
公式
局部公式:a=2mn b=m^2-n^2 c=m^2+n^2 可以得到所有的基本勾股数
完全公式:a=m,b=(m^2 / k - k) / 2,c=(m^2 / k + k) / 2
其中m ≥3
1、当m确定为任意一个 ≥3的奇数时,k={1,m^2的所有小于m的因子}
2、当m确定为任意一个 ≥4的偶数时,k={m^2 / 2的所有小于m的偶数因子
勾股数组数N
一个大于1的正整数n,如果它的标准分解式为n=p1^m1×p2^m2×……×pr^mr,那么它的正因数个数为N=(m1+1)×(m2+1)×……×(mr+1);依据定理,易得以下结论
当a给定时,不同勾股数组a,b,c的组数N等于①式中k的可取值个数
1、取奇数a=p1^m1×p2^m2×……×pr^mr,其中k={1,a^2的所有小于a的因子},则k的可取值个数:
N=[(2m1+1)×(2m2+1)×……×(2mr+1)-1]/2
2、取偶数a=2^m0×p1^m1×p2^m2×……×pr^mr,其中k={a^2 / 2的所有小于a的偶数因子},则k的可取值个数:
N=[(2m0-1)×(2m1+1)×(2m2+1)×……×(2mr+1)-1]/2
其中,p1,p2,……,pr为互不相同的奇素数,m0,m1,……,mr为幂指数。
欧拉常数:
S=1+1/2+1/3+……=0.577215,66490,15328,60606,51209,00824,02431,04215,93359,39923,59880,57672,34884,86772,67776,64670,93694,70632,91746,74951,46314,47249,80708,24809,60504,01448,65428,36224,17399,76449,23536,25350,03337,42937,33773,76739,42792,59525,82470
极限S=lim[1+1/2+1/3+…+1/n-ln(n)](n→∞)存在
欧拉函数
单点判断
int eular(int n)
{
intret=1,i;
for(i=2; i*i<=n; i++)
if(n%i==0)
{
n/=i,ret*=i-1;
while(n%i==0)
n/=i,ret*=i;
}
if(n>1) ret*=n-1;
returnret;
}
打表
int phi[N+1];
void eular()
{
inti,j;
for(i=1;i<=N;i++) phi[i]=i;
for(i=2;i<=N;i++)
{
if (phi[i]==i)
{
for (j=i;j<=N;j+=i)
{
phi[j]=phi[j]/i*(i-1);
}
}
}
}
公约数
gcdStein算法
int gcd(int a, int b)
{
if(a==0) return b;
if(b== 0) return a;
if(a%2==0&&b%2==0) return gcd(a>>1,b>>1)<<1;
elseif(a%2==0) return gcd(a>>1,b);
elseif(b%2==0) return gcd(a,b>>1);
elsereturn gcd((a>b?(a-b):(b-a)),(a<b?a:b));
}
位运算gcd
int binary_gcd(int x,int y)
{
if(x==0) return y;
if(y==0) return x;
intcnt=0,tmp;
while((x|y)&1==0) x>>=1,y>>=1,cnt++;
while(x&1==0) x>>=1;
while(y)
{
while (y&1==0) y>>=1;
int tmp=y;
y=y>x?y-x:x-y;
x=tmp;
}
return x<<=cnt;
}
扩展欧几里德定理
int exGcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
int r = exGcd(b, a % b, x,y);
int t = x;
x = y;
y = t - a / b * y;
return r;
}
p * a+q * b = c的一组解p1 = p0*(c/Gcd(a,b)),q1 =q0*(c/Gcd(a,b)),p * a+q* b = c的其他整数解满足:
p = p1 +b/Gcd(a, b) * t
q = q1 -a/Gcd(a, b) * t(其中t为任意整数)
p 、q就是p * a+q* b = c的所有整数解。
约瑟夫环
scanf("%d%d",&n, &m);
for(i=2; i<=n; i++)
s=(s+m)%i;
二分算法
int Fin(double key) //返回<=key的下标
{
intl=0,r=n-1;
while(l<r)
{
int m=(l+r)>>1;
if (A[m]==key) return m;
else if (A[m]>key) r=m-1;
else if (m==n-1||A[m+1]>key) return m;
else l=m+1;
}
return r;
}
fibonacci数列
F(n)=(1/√5)*{[(1+√5)/2]^n- [(1-√5)/2]^n}
F(n) = [ (( sqrt ( 5 ) + 1 ) / 2) ^ n ]其中[ x ]表示取距离 x 最近的整数。
1.gcd(fib(n),fib(m))=fib(gcd(n,m))
2.如果fib(k)能被x整除,则fib(k*i)都可以被x整除。
3.f(0)+f(1)+f(2)+…+f(n)=f(n+2)-1
4.f(1)+f(3)+f(5)+…+f(2n-1)=f(2n)
5.f(2)+f(4)+f(6)+…+f(2n) =f(2n+1)-1
6.[f(0)]^2+[f(1)]^2+…+[f(n)]^2=f(n)·f(n+1)
7.f(0)-f(1)+f(2)-…+(-1)^n·f(n)=(-1)^n·[f(n+1)-f(n)]+1
8.f(m+n)=f(m-1)·f(n-1)+f(m)·f(n)
9.[f(n)]^2=(-1)^(n-1)+f(n-1)·f(n+1)
10.f(2n-1)=[f(n)]^2-[f(n-2)]^2
11.3f(n)=f(n+2)+f(n-2)
12. f(2n-1)=f(2n)*f(2n-2)+1
13.f(2n-2m-2)[f(2n)+f(2n+2)]=f(2m+2)+f(4n-2m) [ n〉m≥-1,且n≥1]
定理
欧拉定理
A^X% C= A^(X%phi(C)+phi(C)) % C (X>=phi(C))
若n,a为正整数,且n,a互质,(a,n) = 1,则a^φ(n) ≡ 1 (modn)。
欧拉定理表明,若n,a为正整数,且n,a互质,(a,n) = 1,则a^φ(n) ≡ 1 (modn)。
a是不能被质数p整除的正整数,则有a^(p-1) ≡ 1 (modp) 。
当模有原根时,它有个原根。
当且仅当p为素数时:( p -1 )! ≡ -1 ( mod p )
费马小定理
假如p是质数,且(a,p)=1,那么 a^(p-1) ≡1(mod p)
假如p是质数,则:a^p ≡a(mod p)
中国剩余定理
1、若a和b是正整数,则2^a-1模2^b-1的最小正剩余是2^r-1,其中r是a模b的最小正剩余。2、(2^a-1和2^b-1)= 2^(a,b)-1.正整数2^a-1和2^b-1是互素的,当且仅当a与b是互素的。
3、给定两两互素的模m1,m2,…,mr,一个小于M=m1m2…mr的正整数n由它的模mj最小正剩余唯一决定,其中j=1,2,…,r.
反素数
定义
对于任何正整数x,其约数的个数记做g(x).例如g(1)=1,g(6)=4.如果某个正整数x满足:对于任意i(0<i<x),都有g(i)<g(x)。
性质
性质一:一个反素数的质因子必然是从2开始连续的质数.
性质二:p=2^t1*3^t2*5^t3*7^t4.....必然t1>=t2>=t3>=....
反素数表
int rprim[35][2] = {
498960,200,332640,192,277200,180,221760,168,166320,160,
110880,144,83160,128,55440,120,50400,108,45360,100,
27720,96,25200,90,20160,84,15120,80,10080,72,
7560,64,5040,60,2520,48,1680,40,1260,36,
840,32,720,30,360,24,240,20,180,18,
120,16,60,12,48,10,36,9,24,8,
12,6,6,4,4,3,2,2,1,1};
const int size=500000;
int isprime[size+10],atp[size+10][2];
void antiprime()
{
int i,j;
for (i=1;i<=size;i++)
for(j=i;j<=size;j+=i)
atp[j][0]++;
for (i=1;i<=size;i++)
{
atp[i][1]=i;
if (atp[i][0]<atp[i-1][0])
{
atp[i][0]=atp[i-1][0];
atp[i][1]=atp[i-1][1];
}
else if(atp[i][0]==atp[i-1][0]&&
atp[i][1]>atp[i-1][1])
atp[i][1]=atp[i-1][1];
}
}
高斯消元
Hdu 4200
int n,d,row,col,ans;
char g[110][110];
int num[110];
void gauss()
{
inti,j,k;
for(col=row=1;col<=n;col++)
{
for (i=row;i<=n;i++) if (g[i][col]) break;
if (i>n) continue;
if (i!=row) for (j=col;j<=n+1;j++)
k=g[i][j],g[i][j]=g[row][j],g[row][j]=k;
for (i=row+1;i<=n;i++) if (g[i][col])
for (j=col;j<=n+1;j++) g[i][j]^=g[row][j];
row++;
}
return ;
}
void dfs(int k)
{
if(k<=n)
{
num[k]=1,dfs(k+1);
num[k]=0,dfs(k+1);
}
else
{
int i,j;
for (i=row-1;i>0;i--)
{
k=g[i][n+1];
for (j=i+1;j<=n;j++) k^=g[i][j]&&num[j];
num[i]=k;
}
for (i=1,k=0;i<=n;i++) k+=num[i];
ans=min(k,ans);
}
return ;
}
int main()
{
inti,j,k,t,L,R;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&d);
memset(g,0,sizeof(g));
for (i=1;i<=n;i++)
{
scanf("%d",&g[i][n+1]);
L=max(1,i-d);
R=min(n,i+d);
for (j=L;j<=R;j++) g[j][i]=1;
}
ans=110,gauss();
for (i=row;i<=n;i++) if (g[i][n+1]) break;
if (i<=n) ans=-1;
for (i=1;i<row;i++)
{
if (!g[i][i])
{
for (j=i+1;j<=n;j++) if (g[i][j]) break;
if (j>n) break;
for (k=1;k<=n;k++)
R=g[k][j],g[k][j]=g[k][i],g[k][i]=R;
}
}
if (ans>0) dfs(row);
printf(ans==-1?"impossible\n":"%d\n",ans);
}
return 0;
}
DP
母函数模版
#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=121;
int main()
{
intc[maxn],d[maxn];
inti,j,k;
for(i=0; i<maxn; i++)
c[i]=1,d[i]=0;
for(i=2; i<maxn; i++)
{
for(j=0; j<maxn; j++)
{
for(k=0; k+j<maxn; k+=i)
{
d[j+k]+=c[j];
}
}
for(j=0; j<maxn; j++)
{
c[j]=d[j];
d[j]=0;
}
}
while(scanf("%d",&k)!=EOF)
{
printf("%d\n",c[k]);
}
return 0;
}
最长公共上升子序列
O(n^3)
#include<iostream>
usingnamespace std;
constint MAX=501;
//dp[i]表示a中第i个元素的最优解个数,只不过ai需满足bj==ai;
intgcis(int a[], int la, int b[], int lb)
{
int i,j,k,mx,dp[MAX];
memset(dp, 0, sizeof(dp));
for (i=1; i<=la; i++)
for(j=1; j<=lb; j++)
if(a[i-1]==b[j-1])
for(k=1,dp[j]=1; k<j; k++)
if(b[k-1]<b[j-1]&&dp[k]+1>dp[j])
dp[j]=dp[k]+1;
for(i=1; i<=lb; i++)
if (dp[0]<dp[i])
dp[0]=dp[i];
return dp[0];
}
intmain(void)
{
int n,am,bm,a[MAX],b[MAX],i,j;
cin>>n;
j=0;
while(n--)
{
j++;
cin>>am;
for(i=0; i<am; i++) cin>>a[i];
cin>>bm;
for(i=0; i<bm; i++) cin>>b[i];
am=gcis(a,am,b,bm);
printf(j==1?"%d\n":"\n%d\n",am);
}
return 0;
}
O(n^2)
int LCIS(int a[],int b[],int la,int lb)
{
intmaxs;
memset(f,0,sizeof(f));
for(int i=1;i<=la;i++)
{
maxs=0;
for (int j=1;j<=lb;j++)
{
if (a[i]>b[j]&&maxs<f[j]) maxs=f[j];
if (a[i]==b[j]) f[j]=maxs+1;
}
}
for(int j=1;j<=lb;j++) f[0]=Max(f[0],f[j]);
return f[0];
}
最长公共子串
char* LCS(char left[],char right[])
{
int lenLeft=strlen(left),lenRight=strlen(right),k;
char *c=(char *)malloc(lenRight),*p;
int start,end,len,i,j;
end=len=0;//len表示最长公共子串的长度
for(i=0; i<lenLeft; i++) //串1从前向后比较
{
for(j=lenRight-1; j>=0; j--) //串2从后向前比较
{
if(left[i] == right[j])//元素相等时
{
if(i==0||j==0) c[j]=1;
else c[j]=c[j-1]+1;
}
else
c[j] = 0;
if(c[j] > len)
{
len=c[j];
end=j;
}
}
}
start=end-len+1;
p=(char*)malloc(len+1);
for (i=start; i<=end; i++)
p[i-start] = right[i];
p[len]='\0';
return p;
}
最长回文子串 Hdu3068
int solve(char *str)
{
intmx=0,res=0,id;
intn=strlen(str);
c[0]='$',c[1]='#';
for(int i=0;i<n;i++)
c[i*2+2]=str[i],c[i*2+3]='#';
n=n+n+2;
for(int i=1;i<n-1;i++)
{
p[i]=mx>i?min(p[id+id-i],mx-i):1;
for (;c[i-p[i]]==c[i+p[i]];p[i]++);
if (p[i]+i>mx) mx=p[i]+i,id=i;
if (p[i]>res) res=p[i];
}
return res-1;
}
最大m子段和
LL MaxSum(int n,int m,LL *a) //数组a,n个元素必须取m段
{
inti,j,f=0;
LLans;
if(n<m||m<1) return 0;
for(j=0; j<=n; j++) dp[0][j]=dp[1][j]=0;
for(i=1; i<=m; i++)
{
f=1-f;
dp[f][i]=dp[1-f][i-1]+a[i];
ans=dp[1-f][i-1];
for (j=i+1; j<=n-m+i; j++)
{
ans=Max(ans,dp[1-f][j-1]);
dp[f][j]=Max(dp[f][j-1],ans)+a[j];
}
}
for(ans=-INF,i=m; i<=n; i++) ans=Max(ans,dp[f][i]);
return ans;
}
背包
单调队列 poj2823
#include "stdio.h"
#include "string.h"
const int M=1000005;
int arr[M];
int Minq[M],Maxq[M];
int Q[M],Inq[M];
int n,k;
void Min()
{
inthead=1,tail=0;
inti;
for(i=1; i<=n; i++)
{
while(head<=tail && Q[tail]>arr[i])
tail--;
tail++;
Q[tail]=arr[i];
Inq[tail]=i;
if(i>=k)
{
while(Inq[head]<=i-k) head++;
Minq[i-k]=Q[head];
}
}
}
void Max()
{
inthead=1,tail=0;
inti;
for(i=1; i<=n; i++)
{
while(head<=tail && Q[tail]<arr[i])
tail--;
tail++;
Q[tail]=arr[i],Inq[tail]=i;
if(i>=k)
{
while(Inq[head]<=i-k)
head++;
Maxq[i-k]=Q[head];
}
}
}
int main()
{
while(scanf("%d%d",&n,&k)!=EOF)
{
if(k>n) k=n;
int i;
for(i=1; i<=n; i++)
scanf("%d",&arr[i]);
Min();
Max();
for(i=0; i<n-k+1; i++)
printf("%d%c", Minq[i], (i < n - k) ? ' ' : '\n');
for(i=0; i<n-k+1; i++)
printf("%d%c", Maxq[i], (i < n - k) ? ' ' : '\n');
}
return 0;
}
单调队列多重背包hdu 2191
int main()
{
intn,m,cas,i,j,k,y,head,tail;
intp[N],w[N],s[N],f[N],u[N],v[N];
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d",&n,&m);
for(i=0; i<m; i++)
scanf("%d%d%d",&p[i],&w[i],&s[i]);
for(i=0; i<=n; i++) f[i]=0;
for(i=0; i<m; i++)
{
for(j=0; j<p[i]; j++)
{
head=0,tail=-1;
for(k=0; k<=(n-j)/p[i]; k++)
{
y=f[j+k*p[i]]-k*w[i];
while(head<=tail&&u[tail]<=y) tail--;
//去掉队列中不可能为最大值大数据
u[++tail]=y,v[tail]=k;
while(head<=tail&&v[tail]-v[head]>s[i]) head++;
//保证队列首尾差值数量不大于当前物品的数量
f[j+k*p[i]]=u[head]+k*w[i];
}
}
}
printf("%d\n",f[n]);
}
}
分组背包
分组背包每组至少选择一个状态转移方程如下:
dp[i][t]=max(dp[i][t],dp[i][t-p[i][j]]+v[i][j]);
dp[i][t]=max(dp[i][t],dp[i-1][t-p[i][j]]+v[i][j]);
棋盘覆盖
1*len长度状态搜索
void dfs(int pre,int now,int pos,int len) //p_len=len^len
{
if (pos<0) return ;
if (pos==0)
{
state[top][0]=pre,state[top++][1]=now;
return ;
}
for (int i=0;i<len;i++)
dfs(pre*len+i,now*len+((i+len-1)%len),pos-1,len);
dfs(pre*p_len,now*p_len,pos-len,len);
}
数据结构
日期函数
intdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
struct date{
intyear,month,day;
};
//判闰年
inline int leap(int year){
return(year%4==0&&year%100!=0)||year%400==0;
}
//判合法性
inline int legal(date a){
if(a.month<0||a.month>12)
return0;
if(a.month==2)
returna.day>0&&a.day<=28+leap(a.year);
returna.day>0&&a.day<=days[a.month-1];
}
//比较日期大小
inline int datecmp(date a,date b){
if(a.year!=b.year)
return a.year-b.year;
if(a.month!=b.month)
return a.month-b.month;
return a.day-b.day;
}
//返回指定日期是星期几
int weekday(date a){
inttm=a.month>=3?(a.month-2):(a.month+10);
intty=a.month>=3?a.year:(a.year-1);
return(ty+ty/4-ty/100+ty/400+(int)(2.6*tm-0.2)+a.day)%7;
}
//日期转天数偏移
int date2int(date a){
intret=a.year*365+(a.year-1)/4-(a.year-1)/100+(a.year-1)/400,i;
days[1]+=leap(a.year);
for(i=0;i<a.month-1;ret+=days[i++]);
days[1]=28;
returnret+a.day;
}
//天数偏移转日期
date int2date(int a){
dateret;
ret.year=a/146097*400;
for(a%=146097;a>=365+leap(ret.year);a-=365+leap(ret.year),ret.year++);
days[1]+=leap(ret.year);
for(ret.month=1;a>=days[ret.month-1];a-=days[ret.month-1],ret.month++);
days[1]=28;
ret.day=a+1;
returnret;
}
星期几
W[][20]={"monday","tuesday", "wednesday","thursday","friday", "saturday", "sunday"}
int Week(int y,int m,int d) //y表示年份,m表示月份,d表示天数
{
int a;
// 1月2月当作前一年的13,14月
if (m == 1 || m == 2)
m+= 12,y--;
// 判断是否在1752年9月3日之前
if ((y < 1752) || (y == 1752 && m < 9) ||
(y == 1752 && m == 9 && d < 3))
a = (d + 2*m + 3*(m+1)/5 + y + y/4 +5) % 7;
else
a = (d + 2*m + 3*(m+1)/5 + y + y/4 - y/100 + y/400)%7;
return a;
}
STL
1.sort(vi.begin(), vi.end()); // 从小到大
2.reverse(vi.begin(),vi.end()) // 从大到小
3.vector<int>::iterator it;
4.it=find(v.begin(),v.end(),value);
5.v.push_back(value); void pop_back();
6.v.empty(); v.size();v..resize();
7.for(vector<string>::size_type i = 0;;);
8.v.erase(pos) // 删除pos位置的数据,传回下一个数据的位置;
9.v.erase(v.begin(),v.end());
10.v.clear() ; v.front() ;
11.v.insert(pos,elem) 在pos(指针)位置插入一个elem拷贝;
12.v.insert(pos,n,elem) // 在pos位置插入n个elem数据,无返回值 ;
13.v.insert(pos,beg,end) // 在pos位置插入在[beg,end)区间的数据;无返回值;
14.v.rend() 传回一个逆向队列的最后一个数据的下一个位置;
15.v.max_size() 返回容器中最大数据的数量;
16.v.rbegin() 传回一个逆向队列的第一个数据;
17.v.assign(beg,end) 将(beg; end)区间中的数据赋值给c;
18.v.assign(n,elem) 将n个elem的拷贝赋值给c;
19.v. at(idx) 传回索引idx所指的数据,如果idx越界,抛出out_of_range;
20.c.erase(beg,end) 删除[beg,end)区间的数据,传回下一个数据的位置;
21.vector<int> v(first,last);
22.vector<int> v2(n,0);
23.vector<int> v3(v2);
24.v.swap(v2);
iteratorbegin();返回指向当前集合中第一个元素的迭代器。
voidclear();清除当前集合中的所有元素。
count返回当前集合中出现的某个值的元素的数目。
boolempty();如果当前集合为空,返回true;否则返回false。
equal_range语法: pair equal_range( const key_type &key );
返回集合中与给定值相等的上下限的两个迭代器。
voiderase(iterator i ); 删除i元素;
voiderase(iterator start,iterator end ); 删除从start开始到end结束的元素;
size_typeerase( const key_type &key ); 删除key值所有元素(返回被删除元素的个数)。
find:在当前集合中查找等于key值的元素,并返回指向该元素的迭代器;如果没有找到,返回指向集合最后一个元素的迭代器。
insert
iteratorinsert(iterator i, constTYPE &val ); 在迭代器i前插入val;
voidinsert(input_iterator start,input_iterator end );
将迭代器start开始到end结束返回内的元素插入到集合中;
pairinsert( constTYPE &val ); 在当前集合中插入val元素,并返回指向该元素的迭代器和一个布尔值来说明val是否成功的被插入了。(应该注意的是在集合(Sets)中不能插入两个相同的元素。)
lower_bound
返回一个指向大于或者等于key值的第一个元素的迭代器。
upper_bound
在当前集合中返回一个指向大于Key值的元素的迭代器.
Swap::voidswap( set &object );
交换当前集合和object集合中的元素。
排序
快速排序
void qs(int *arr,int left,int right)
{
if(left>=right) return ;
int compare=arr[left],i=left,j=right;
while(i<j)
{
while (i<j&&arr[j]>compare) j--;
arr[i]=arr[j];
while (i<j&&arr[i]<=compare) i++;
arr[j]=arr[i];
}
arr[i]=compare;
qs(arr,left,i-1);
qs(arr,i+1,right);
}
归并排序
voidmerge(int *arr,int *brr,int left,int mid,int right)
{
int i=left,j=mid+1,k=left;
while (i<=mid&&j<=right)
arr[i]<arr[j]?(brr[k++]=arr[i++]):(brr[k++]=arr[j++]);
while (i<=mid) brr[k++]=arr[i++];
while (j<=right) brr[k++]=arr[j++];
for (i=left;i<=right;i++)arr[i]=brr[i];
}
voidmsort(int *arr,int *brr,int left,int right)
{
if (left>=right) return ;
int mid=(left+right)>>1;
msort(arr,brr,left,mid);
msort(arr,brr,mid+1,right);
merge(arr,brr,left,mid,right);
}
线段树
区间取反Hdu3397
const intsize=111111;
struct Node
{
int lc,mc,rc;
int lz,mz,rz;
int sum,lazy;
int xr,len;
}tre[size<<2];
void pushup(intrt,int k)
{
int r1=rt<<1,r2=r1|1;
int rs=k>>1,ls=k-(k>>1);
tre[rt].sum=tre[r1].sum+tre[r2].sum;
if (tre[r1].lc==ls)tre[rt].lc=tre[r1].lc+tre[r2].lc;
else tre[rt].lc=tre[r1].lc;
if (tre[r2].rc==rs)tre[rt].rc=tre[r1].rc+tre[r2].rc;
else tre[rt].rc=tre[r2].rc;
tre[rt].mc=Max(tre[r1].rc+tre[r2].lc,Max(tre[r1].mc,tre[r2].mc));
if (tre[r1].lz==ls)tre[rt].lz=tre[r1].lz+tre[r2].lz;
else tre[rt].lz=tre[r1].lz;
if (tre[r2].rz==rs)tre[rt].rz=tre[r1].rz+tre[r2].rz;
else tre[rt].rz=tre[r2].rz;
tre[rt].mz=Max(tre[r1].rz+tre[r2].lz,Max(tre[r1].mz,tre[r2].mz));
}
void build(intrt,int l,int r)
{
tre[rt].lazy=-1;
tre[rt].xr=0;
tre[rt].len=r-l+1;
if (l==r)
{
int v;
scanf("%d",&v);
tre[rt].lc=tre[rt].mc=tre[rt].rc=tre[rt].sum=v;
tre[rt].lz=tre[rt].mz=tre[rt].rz=(v?0:1);
return ;
}
int m=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
pushup(rt,r-l+1);
}
void change(intrt)
{
int t;
t=tre[rt].lc;
tre[rt].lc=tre[rt].lz;
tre[rt].lz=t;
t=tre[rt].mc;
tre[rt].mc=tre[rt].mz;
tre[rt].mz=t;
t=tre[rt].rc;
tre[rt].rc=tre[rt].rz;
tre[rt].rz=t;
}
void Txor(int rt)
{
if (tre[rt].lazy>=0)tre[rt].lazy=1-tre[rt].lazy;
else tre[rt].xr^=1;
}
void pushdown(intrt,int k)
{
int v=tre[rt].lazy;
int r1=rt<<1,r2=r1|1;
int ls=k-(k>>1),rs=k>>1;
if (v!=-1)
{
tre[r1].lc=tre[r1].mc=tre[r1].rc=tre[r1].sum=(v?ls:0);
tre[r1].lz=tre[r1].mz=tre[r1].rz=(v?0:ls);
tre[r2].lc=tre[r2].mc=tre[r2].rc=tre[r2].sum=(v?rs:0);
tre[r2].lz=tre[r2].mz=tre[r2].rz=(v?0:rs);
tre[r1].xr=tre[r2].xr=0;
tre[r1].lazy=tre[r2].lazy=tre[rt].lazy;
tre[rt].lazy=-1;
}
if (tre[rt].xr)
{
Txor(r1);
Txor(r2);
tre[r1].sum=ls-tre[r1].sum;
tre[r2].sum=rs-tre[r2].sum;
change(r1);
change(r2);
tre[rt].xr=0;
}
}
void update(intrt,int l,int r,int L,int R,int v)
{
if (L<=l&&r<=R)
{
int k=r-l+1;
if (v==2)
{
change(rt);
tre[rt].sum=k-tre[rt].sum;
tre[rt].xr^=1;
}
else
{
tre[rt].lc=tre[rt].mc=tre[rt].rc=tre[rt].sum=(v?k:0);
tre[rt].lz=tre[rt].mz=tre[rt].rz=(v?0:k);
tre[rt].lazy=v;
tre[rt].xr=0;
}
return ;
}
if (l==r) return ;
pushdown(rt,r-l+1);
int m=(l+r)>>1;
if (L<=m) update(rt<<1,l,m,L,R,v);
if (R>m) update(rt<<1|1,m+1,r,L,R,v);
pushup(rt,r-l+1);
}
Node query(intrt,int l,int r,int L,int R)
{
Node tmp= {0};
if (L<=l&&r<=R) returntre[rt];
if (l==r) return tmp;
pushdown(rt,r-l+1);
int m=(l+r)>>1,f1=0,f2=0;
Node r1,r2;
if (L<=m)
{
r1=query(rt<<1,l,m,L,R);
f1=1;
}
if (R>m)
{
r2=query(rt<<1|1,m+1,r,L,R);
f2=1;
}
if (f1&&f2)
{
tmp.len=r1.len+r2.len;
if (r1.len==r1.lc) tmp.lc=r1.lc+r2.lc;
else tmp.lc=r1.lc;
if (r2.rc==r2.len) tmp.rc=r1.rc+r2.rc;
else tmp.rc=r2.rc;
tmp.mc=Max(r1.rc+r2.lc,Max(r1.mc,r2.mc));
}
else if (f1) tmp=r1;
else tmp=r2;
return tmp;
}
int querysum(intrt,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return tre[rt].sum;
if (l==r) return 0;
pushdown(rt,r-l+1);
int m=(l+r)>>1,res=0;
if (L<=m)res+=querysum(rt<<1,l,m,L,R);
if (R>m) res+=querysum(rt<<1|1,m+1,r,L,R);
return res;
}
int main()
{
int ncase,n,q,op,a,b;
scanf("%d",&ncase);
while (ncase--)
{
scanf("%d %d",&n,&q);
n--;
build(1,0,n);
while (q--)
{
scanf("%d %d%d",&op,&a,&b);
if (a>b) a^=b,b^=a,a^=b;
if (op<3) update(1,0,n,a,b,op);
else if (op==3)printf("%d\n",querysum(1,0,n,a,b));
else
{
Node tmp=query(1,0,n,a,b);
printf("%d\n",tmp.mc);
}
}
}
return 0;
}
Uva11983 矩形k次交
#include<cstdio>
#include<iostream>
#include<algorithm>
#define LL long long
using std::sort;
const int nsize=33333;
struct Line
{
intlx,rx,y,f;
Line(){}
Line(inta,int b,int c,int d): lx(a),rx(b),y(c),f(d){}
booloperator <(const Line &cmp) const{
returny<cmp.y;
}
}line[nsize<<1];
int X[nsize<<1],top,k;
int sum[nsize<<3][11]; //记录覆盖i次及以上的长度
int num[nsize<<3];
int Fin(int key,int len)
{
intl=0,r=len;
while(l<=r)
{
intm=(l+r)>>1;
if(X[m]>key) r=m-1;
elseif (X[m]<key) l=m+1;
elsereturn m;
}
return -1;
}
void build(int rt,int l,int r)
{
num[rt]=0;
sum[rt][0]=X[r+1]-X[l];
for (inti=1;i<=k;i++) sum[rt][i]=0;
if (l==r)return ;
intm=(l+r)>>1;
build(rt<<1,l,m);
build(rt<<1|1,m+1,r);
}
void PushUp(int rt,int l,int r)
{
inti,t1=rt<<1,t2=t1|1;
if(num[rt])
{
for(i=1;i<=k;i++)
{
if(num[rt]>=i) sum[rt][i]=X[r+1]-X[l];
else if (l==r) sum[rt][i]=0;
else sum[rt][i]=sum[t1][i-num[rt]]+sum[t2][i-num[rt]];
}
}
else
{
for(i=1;i<=k;i++)
if(l==r) sum[rt][i]=0;
else sum[rt][i]=sum[t1][i]+sum[t2][i];
}
}
void update(int rt,int l,int r,int L,int R,int v)
{
if(L<=l&&r<=R)
{
num[rt]+=v;
PushUp(rt,l,r);
return;
}
intm=(l+r)>>1;
if(L<=m) update(rt<<1,l,m,L,R,v);
if(R>m) update(rt<<1|1,m+1,r,L,R,v);
PushUp(rt,l,r);
}
int main()
{
LL ans;
intT,cas=0;
intn,m,i,j,L,R;
intx1,x2,y1,y2;
scanf("%d",&T);
while(T--)
{
scanf("%d %d",&n,&k);
for(top=i=0;i<n;i++)
{
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
x2++,y2++;
line[top]={x1,x2,y1,1}; X[top++]=x1;
line[top]={x1,x2,y2,-1}; X[top++]=x2;
}
sort(X,X+top);
sort(line,line+top);
for(m=0,i=1;i<top;i++)
if(X[i]!=X[i-1]) X[++m]=X[i];
build(1,0,m);
for (ans=i=0;i<top-1;i++)
{
L=Fin(line[i].lx,m);
R=Fin(line[i].rx,m)-1;
if(L<=R) update(1,0,m,L,R,line[i].f);
ans+=1LL*sum[1][k]*(line[i+1].y-line[i].y);
}
printf("Case %d: %lld\n",++cas,ans);
}
return 0;
}
最大子矩阵
poj1050最大子矩阵
int maxsum2(int *a)
{
intsum=-INF,b=0;
for (inti=1;i<=n;i++)
{
if(b>0) b+=a[i];
elseb=a[i];
sum=sum>b?sum:b;
}
returnsum;
}
int maxsum(int a[size+10][size+10])
{
inti,j,k,tmp;
intsum=-INF;
intb[size+10];
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++) b[j]=0;
for(j=i;j<=n;j++)
{
for (k=1;k<=n;k++) b[k]+=a[j][k];
tmp=maxsum2(b);
sum=sum>tmp?sum:tmp;
}
}
returnsum;
}
字符串
函数
Sscanf函数
1、取指定长度的字符串
sscanf("123456 ", "%4s", buf);
printf("%s\n", buf);
结果为:1234
2、取到指定字符为止的字符串。
sscanf("123456 abcdedf", "%[^]", buf);
printf("%s\n", buf);
结果为:123456
3、取仅包含指定字符集的字符串。(遇到即停)
sscanf("123456abcdedfBCDEF","%[1-9a-z]", buf);
printf("%s\n", buf);
结果为:123456abcdedf
sscanf("123456abcdedfBCDEF","%[1-9A-Z]",buf);
printf("%s\n",buf);
结果为:123456
4、取到指定字符集为止的字符串。
sscanf("123456abcdedfBCDEF","%[^A-Z]", buf);
printf("%s\n", buf);
结果为:123456abcdedf
5、给定一个字符串iios/12DDWDFF@122,获取 / 和 @ 之间的字符串,先将 "iios/"过滤掉,再将非'@'的一串内容送到buf中
sscanf("iios/12DDWDFF@122","%*[^/]/%[^@]", buf);
printf("%s\n", buf);
结果为:12DDWDFF
6、s[100]=”2006:03:18-2006:04:18”
sscanf(s,"%[0-9,:]-%[0-9,:]",str1,str2);
sscanf(s,"%[^-]-%s",str1,str2);
sscanf(str1, "%d:%d:%d", &a, &b,&c);
printf("%s\n2:%s\n",str1,str2);
Sprintf函数
1.sprintf用于格式化字符串
把变量打印到字符串中,从而获得数字的字符形式,这样不需要手工转换。
例如
char c[100];int k=255;
sprintf(c,"%d",k);
//c包含"255"
2.sprintf用于进制转换
可以方便地得到变量的十六进制和八进制字符序列,再稍加处理即可得到每一位的值。
char c[100];
int k=255;
sprintf(c,"%x",k);
//c包含"ff" c[0]='f' c[1]='f'
3.sprintf用于连接字符串
方便地连接两个或者多个字符串
char buf[1024];
char a[100]="I ";
char b[100]="love ";
char c[100]="ACM."
sprintf(buf,"%s%s%s",a,b,c);
//buf 包含"I love ACM."
Strtok函数
char s[1000]; //以字符" ,."分割s字符串
while(~scanf("%s",s))
{
char*p=strtok(s," ,.");
while(p)
{
printf("%s\n",p);
p=strtok(NULL," ,.");
}
char*q=s;
inti=0;
char*r[100];
while(r[i++]=strtok(q," ,."))
{
printf("%s\n",p);
q=NULL;
}
}
KMP算法
void get_next(char* T)
{
inti=0,j=-1;
next[0]=-1,len=strlen(T);
while(i<len)
{
if(j==-1||T[i]==T[j])
{
++i,++j;
if (T[i]!=T[j]) next[i]=j;
else next[i]=next[j];
}
else j=next[j];
}
}
最小字典序字符串
int search(int len)
{
inti=0,j=1,k=0,t;
while(i<len&&j<len)
{
t=str[(i+k)%len]-str[(j+k)%len];
if(!t) k++;
elseif (t<0) j+=k+1,k=0;
elsei+=k+1,k=0;
if(i==j) j++;
}
return i;
}
计算几何
网格
#define abs(x) ((x)>0?(x):-(x))
struct point{int x,y;};
int gcd(int a,int b){
returnb?gcd(b,a%b):a;
}
//多边形上的网格点个数
int grid_onedge(int n,point* p){
inti,ret=0;
for(i=0;i<n;i++)
ret+=gcd(abs(p[i].x-p[(i+1)%n].x),abs(p[i].y-p[(i+1)%n].y));
returnret;
}
//多边形内的网格点个数
int grid_inside(int n,point* p){
inti,ret=0;
for(i=0;i<n;i++)
ret+=p[(i+1)%n].y*(p[i].x-p[(i+2)%n].x);
return(abs(ret)-grid_onedge(n,p))/2+1;
}
几何公式
三角形:
1. 半周长P=(a+b+c)/2
2. 面积S=aHa/2=absin(C)/2=sqrt(P(P-a)(P-b)(P-c))
3. 中线Ma=sqrt(2(b^2+c^2)-a^2)/2=sqrt(b^2+c^2+2bccos(A))/2
4. 角平分线Ta=sqrt(bc((b+c)^2-a^2))/(b+c)=2bccos(A/2)/(b+c)
5. 高线Ha=bsin(C)=csin(B)=sqrt(b^2-((a^2+b^2-c^2)/(2a))^2)
6. 内切圆半径r=S/P=asin(B/2)sin(C/2)/sin((B+C)/2)
=4Rsin(A/2)sin(B/2)sin(C/2)=sqrt((P-a)(P-b)(P-c)/P)
=Ptan(A/2)tan(B/2)tan(C/2)
7. 外接圆半径R=abc/(4S)=a/(2sin(A))=b/(2sin(B))=c/(2sin(C))
8. 三角形内切圆半径:r=2*s/(a+b+c);
9. 三角形外接圆半径为R=(a*b*c)/(s*4);
10.s是三角形面积 a,b,c是三角形三边。11.S=√[p(p-a)(p-b)(p-c)]=1/2*a*b*sinC
12. 对角线定理 :在△ABC中,BD平分∠ABC,则AD:DC=AB:BC
四边形:
D1,D2 为对角线,M 对角线中点连线,A 为对角线夹角
1.a^2+b^2+c^2+d^2=D1^2+D2^2+4M^2
2. S=D1D2sin(A)/2
(以下对圆的内接四边形)
3. ac+bd=D1D2
4.S=sqrt((P-a)(P-b)(P-c)(P-d)),P 为半周长
正n 边形:
R 为外接圆半径,r 为内切圆半径
1. 中心角A=2PI/n
2. 内角C=(n-2)PI/n
3. 边长a=2sqrt(R^2-r^2)=2Rsin(A/2)=2rtan(A/2)
4. 面积S=nar/2=nr^2tan(A/2)=nR^2sin(A)/2=na^2/(4tan(A/2))
圆:
1. 弧长l=rA
2. 弦长a=2sqrt(2hr-h^2)=2rsin(A/2)
3. 弓形高h=r-sqrt(r^2-a^2/4)=r(1-cos(A/2))=atan(A/4)/2
4. 扇形面积S1=rl/2=r^2A/2
5. 弓形面积S2=(rl-a(r-h))/2=r^2(A-sin(A))/2
棱柱:
1. 体积V=Ah,A 为底面积,h 为高
2. 侧面积S=lp,l 为棱长,p 为直截面周长
3. 全面积T=S+2A
棱锥:
1. 体积V=Ah/3,A 为底面积,h 为高
(以下对正棱锥)
2. 侧面积S=lp/2,l 为斜高,p 为底面周长
3. 全面积T=S+A
棱台:
1. 体积V=(A1+A2+sqrt(A1A2))h/3,A1.A2 为上下底面积,h 为高
(以下为正棱台)
2. 侧面积S=(p1+p2)l/2,p1.p2 为上下底面周长,l 为斜高
3. 全面积T=S+A1+A2
圆柱:
1. 侧面积S=2PIrh
2. 全面积T=2PIr(h+r)
3. 体积V=PIr^2h
圆锥:
1. 母线l=sqrt(h^2+r^2)
2. 侧面积S=PIrl
3. 全面积T=PIr(l+r)
4. 体积V=PIr^2h/3
圆台:
1. 母线l=sqrt(h^2+(r1-r2)^2)
2. 侧面积S=PI(r1+r2)l
最近点对 Hdu1007
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define size 100000
struct pint
{
double x, y;
} jeo[size];
bool cmpx(const int &a, const int &b)
{
return jeo[a].x < jeo[b].x;
}
bool cmpy(const int &a, const int &b)
{
return jeo[a].y < jeo[b].y;
}
double dis(int &a, int &b)
{
return sqrt((jeo[a].x - jeo[b].x) * (jeo[a].x - jeo[b].x) + (jeo[a].y -jeo[b].y) * (jeo[a].y - jeo[b].y));
}
int n, idx[size], idy[size];
double judge(int l, int r)
{
if (r- l == 1) return dis(idx[l], idx[r]);
if (r- l == 2)
return min(dis(idx[l], idx[l + 1]), min(dis(idx[l + 1], idx[l + 2]),dis(idx[l + 2], idx[l])));
intmid = (l + r) >> 1;
double ans = min(judge(l, mid), judge(mid + 1, r));
intnum = 0;
for(int i = l; i <= r; i++)
if (jeo[idx[i]].x >= jeo[idx[mid]].x -ans && jeo[idx[i]].x <= jeo[idx[mid]].x + ans)
idy[num++] = idx[i];
sort(idy, idy + num, cmpy);
for(int i = 0; i < num; i++)
for(int j = i + 1; j < num; j++)
{
if (jeo[idy[j]].y - jeo[idy[i]].y >= ans) break;
ans = min(ans, dis(idy[j], idy[i]));
}
return ans;
}
int main()
{
while(scanf("%d", &n) && n)
{
for(int i = 0; i < n && scanf("%lf%lf",&jeo[i].x, &jeo[i].y); i++)
idx[i] = i;
sort(idx, idx + n, cmpx);
printf("%.2f\n", judge(0, n - 1) * 0.5);
}
return 0;
}
叉乘法求任意多边形面积
语法:result=polygonarea(Point *polygon,int N); | ||
参数: | ||
*polygon: | 多变形顶点数组 | |
N: | 多边形顶点数目 | |
返回值: | 多边形面积 | |
注意: |
| |
| 支持任意多边形,凹、凸皆可 | |
| 多边形顶点输入时按顺时针顺序排列 | |
源程序: |
| |
typedefstruct { double polygonarea(Point *polygon,int N) for (i=0;i<N;i++) { area /= 2; |
| |
博弈
威佐夫博弈hdu~1527/poj~1067
#include<stdio.h>
#include<math.h>
#define Q (1.0+sqrt(5))/2
int main()
{
int a,b,k;
while (~scanf("%d%d",&a,&b))
{
if (a>b) { k=a; a=b; b=k; }
k=b-a;
k=(int)(k*Q);
if (k==a)printf("0\n");
elseprintf("1\n");
}
return 0;
}
Nim博弈
Hdu1907 n堆石头
#include<stdio.h>
int main()
{
int n,t,i,s,k,cnt;
scanf("%d",&t);
while (t--)
{
scanf("%d",&n);
s=0,cnt=0;
for (i=0;i<n;i++)
{
scanf("%d",&k);
s^=k;
if (k>1)cnt++;
}
if(cnt==0&&s || cnt>=2&&s==0) printf("Brother\n");
else printf("John\n");
}
return 0;
}
SG函数
思路
F 用一个n元组(a1, a2, …, an),来描述游戏过程中的一个局面。
F 用符号#S,表示局面S所对应的二进制数。
F 用符号$(x),表示局面(x)的下一步所有可能出现的局面的集合。
F 定义集合g(x):设$(x)={S1, S2,…, Sk},则g(x)={#S1,#S2, …, #Sk}。
F 令非负整数集为全集,集合G(x)表示集合g(x)的补集。
F 定义函数f(n):f(n)=min{G(n)},即f(n)等于集合G(n)中的最小数。
F 设局面S=(a1, a2, …,an),#S=f(a1)+f(a2)+…+f(an),采用二进制数的加法。
*若#S≠0,则先行者有必胜策略;若#S=0,则后行者有必胜策略。
2 适用范围和限制条件:
Ø 甲乙两人取石子游戏及其类似的游戏;
Ø 每一步只能对某一堆石子进行操作;
Ø 每一步操作的限制,只与这堆石子的数目或一些常数有关;
Ø 操作在有限步内终止,并不会出现循环;
Ø 谁无法继续操作,谁就是输家。
Hdu 1536
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int N=1000010;
const int M=110;
int s[M],num,dp[N];
int getsg(int k)
{
bool v[M];
int i,temp;
memset(v,true,sizeof(v));
for (i=0;i<num;i++)
{
if (k<s[i]) break;
temp=k-s[i];
if(temp>=0&&dp[temp]==-1) dp[temp]=getsg(temp);
v[dp[temp]]=false;
}
for (i=0;;i++) if (v[i])return i;
}
int main()
{
int i,j,k,t,c,d;
while(scanf("%d",&num)&&num)
{
for(i=0;i<num;i++) scanf("%d",s+i);
memset(dp,-1,sizeof(dp));
dp[0]=0;
sort(s,s+num);
scanf("%d",&t);
for (j=0;j<t;j++)
{
scanf("%d",&k);
for(i=c=0;i<k;i++)
{
scanf("%d",&d);
if(d>=0) dp[d]= dp[d]==-1? getsg(d):dp[d];
if(d>=0) c^=dp[d];
}
printf(c>0?"W":"L");
}
printf("\n");
}
return 0;
}
图论
搜索
Hdu 1428 优先队列广搜+记忆化搜索
#include<stdio.h>
#include<string.h>
#include<queue>
const int nsize=55;
int mark[nsize][nsize];
int map[nsize][nsize],n;
__int64 dp[nsize][nsize];
int dir[4][2]= {0,1,0,-1,1,0,-1,0};
struct Node
{
int x,y,time;
friend bool operator < (Node x1,Node x2) //优先队列,时间小的先出队
{
return x1.time > x2.time;
}
};
bool isboundary(int x,int y)
{
if (x<1||x>n||y<1||y>n) return false;
return true;
}
void bfs()
{
priority_queue<Node>q;
Node cur,next;
cur.x=n; cur.y=n;//从(n,n)开始往前找,每次找最小时间到达(n,n)
cur.time=map[n][n];
mark[n][n]=false;
q.push(cur);
while(!q.empty())
{
cur=q.top();
q.pop();
for(int i=0; i<4; i++)
{
next.x=cur.x+dir[i][0];
next.y=cur.y+dir[i][1];
if(isboundary(next.x,next.y)&&mark[next.x][next.y])
{
mark[next.x][next.y]=false;
map[next.x][next.y]+=cur.time;//在原数组记录每个点到终点的最短时间
next.time=map[next.x][next.y];
q.push(next);
}
}
}
}
__int64 dfs(int x,int y)
{
if(dp[x][y]>0) return dp[x][y];
for(int i=0; i<4; i++)
{
int v=x+dir[i][0];
int u=y+dir[i][1];
if(isboundary(u,v)&&map[x][y]>map[v][u])//保证离终点原来越近
dp[x][y]+=dfs(v,u);
}
return dp[x][y];
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
memset(dp,0,sizeof(dp));
memset(mark,true,sizeof(mark));
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
scanf("%d",&map[i][j]);
bfs();
dp[n][n]=1;
printf("%I64d\n",dfs(1,1));
}
return 0;
}
其他
补码
7的原码(10000111)→按位取反(11111000)(负数符号位不变)→加1(11111001)
输入输出
含空格字符串输入 while (fgets(s,MAXN,stdin)!=NULL)
数字外挂输入:
void Scan(long long&T)
{
char C;bool F=0;
for(;C=getchar(),C<'0'||C>'9';)if(C=='-')F=1;
for(T=C-'0';C=getchar(),C>='0'&&C<='9';T=T*10+C-'0');
F&&(T=-T);
}
Scan(N) //输入正负数N
文件输入输出
1、重定向
freopen("in","r",stdin);
freopen("out","w",stdout);
2、非重定向
FILE *fin,*fout;
fin=fopen("in","rb");
fout=fopen("out","wb");
fscanf(fin,"%d",&x);
fprintf(fout,"%d",y);
fclose(fin),fclose(fout);
3、#ifdef __ASD__
freopen("input.txt", "r", stdin); freopen("output.txt", "w", stdout);
#endif
注意:
1.给定区间[a,b]时,考虑a和b的大小;
2.Hdu 输出用%I64d;
3.输出时,每组数据是否要换行;
4.测试数据时,重复测两次,以免初始化错误。
5.数据之和之积是否会超int;
6.根据数据范围判断用什么方法;
7.线段树注意初始化,慢慢打不要有笔误,看清题目条件,又栽了一次;
8.考虑特殊数据,极限数据;
9.拓栈#pragma comment(linker, "/STACK:1024000000,1024000000")
int size = 256 << 20; // 256MB
char *p = (char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p) );
做题方法
数学
1、 打表找规律,循环节;
2、 反向思考求补集;
3、 中间过程溢出;
动态规划
1、状态转移方程
2、注意赋值顺序
3、注意初始化数组是否要初始化到最大下标
4、注意状态转移下一次循环是否要到之前的值
5、状态转移时,当前点状态对之前有影响,