算法板子-一些小问题

graham处理凸包

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
const int MAXN=100002;
struct point
{
    double x,y;
};
point list[MAXN];
int stack[MAXN],top;
double cross(point p0,point p1,point p2) 
{
    return ((p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x));
}
double dis(point p1,point p2)  
{
    return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(double)(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
    double tmp=cross(list[0],p1,p2);
    if(tmp>0) return true;
    else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
    else return false;
}
void graham(int n)
{
    int i;
    if(n==2)
    {
        top=1;
        stack[0]=0;
        stack[1]=1;
    }
    if(n>2)
    {
        for(i=0;i<=1;i++) stack[i]=i;
        top=1;
        for(i=2;i<n;i++)
        {
            while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;
            top++;
            stack[top]=i;
        }
    }
}
int main()
{
    int n,i;
    double ans;
     scanf("%d",&n);
     point p0;
    scanf("%lf%lf",&list[0].x,&list[0].y);
    p0.x=list[0].x;
    p0.y=list[0].y;
    int k=0;
    for(i=1;i<n;i++)
    {
        scanf("%lf%lf",&list[i].x,&list[i].y);
        if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
        {
            p0.x=list[i].x;
            p0.y=list[i].y;
            k=i;
        }
    }
    list[k]=list[0];
    list[0]=p0; 
    sort(list+1,list+n,cmp);
        ans=0.0;
        graham(n);
        if(n==2)
        {
            printf("%.2f 0.00",dis(list[stack[0]],list[stack[1]]));
            return 0;
        }
        for(int i=1;i<=top;i++)
            ans+=dis(list[stack[i]],list[stack[i-1]]);
        ans+=dis(list[stack[0]],list[stack[top]]);
        printf("%.2f ",ans);
        ans=0;
        for(int i=1;i<top;i++)
        {
         ans+=cross(list[stack[0]],list[stack[i]],list[stack[i+1]]);
  }
  ans=fabs(ans)/2;
  printf("%.2lf",ans);
     return 0;
}

FFT多项式相乘

题目描述

给定一个 n 次多项式 F(x),和一个 m次多项式 G(x)。
请求出 F(x)和 G(x)的卷积。

输入格式

第一行 2个正整数n,m。
接下来一行n+1 个数字,从低到高表示F(x) 的系数。
接下来一行m+1 个数字,从低到高表示 G(x) 的系数。

输出格式

一行n+m+1 个数字,从低到高表示 F(x)∗G(x) 的系数。


 #include
#include
#include
using namespace std;
const int MAXN=1e7+10;
inline int read()
{
    char c=getchar();int x=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}
const double Pi=acos(-1.0);
struct complex
{
    double x,y;
    complex (double xx=0,double yy=0){x=xx,y=yy;}
}a[MAXN],b[MAXN];
complex operator + (complex a,complex b){ return complex(a.x+b.x , a.y+b.y);}
complex operator - (complex a,complex b){ return complex(a.x-b.x , a.y-b.y);}
complex operator * (complex a,complex b){ return complex(a.x*b.x-a.y*b.y , a.x*b.y+a.y*b.x);}//不懂的看复数的运算那部分 
int N,M;
int l,r[MAXN];
int limit=1;
void fast_fast_tle(complex *A,int type)
{
    for(int i=0;i<limit;i++) 
        if(i<r[i]) swap(A[i],A[r[i]]);//求出要迭代的序列 
    for(int mid=1;mid<limit;mid<<=1)//待合并区间的中点
    {
        complex Wn( cos(Pi/mid) , type*sin(Pi/mid) ); //单位根 
        for(int R=mid<<1,j=0;j<limit;j+=R)//R是区间的右端点,j表示前已经到哪个位置了 
        {
            complex w(1,0);//幂 
            for(int k=0;k<mid;k++,w=w*Wn)//枚举左半部分 
            {
                 complex x=A[j+k],y=w*A[j+mid+k];//蝴蝶效应 
                A[j+k]=x+y;
                A[j+mid+k]=x-y;
            }
        }
    }
}
int main()
{
    int N=read(),M=read();
    for(int i=0;i<=N;i++) a[i].x=read();
    for(int i=0;i<=M;i++) b[i].x=read();
    while(limit<=N+M) limit<<=1,l++;
    for(int i=0;i<limit;i++)
        r[i]= ( r[i>>1]>>1 )| ( (i&1)<<(l-1) ) ;
    // 在原序列中 i 与 i/2 的关系是 : i可以看做是i/2的二进制上的每一位左移一位得来
    // 那么在反转后的数组中就需要右移一位,同时特殊处理一下复数 
    fast_fast_tle(a,1);
    fast_fast_tle(b,1);
    for(int i=0;i<=limit;i++) a[i]=a[i]*b[i];
    fast_fast_tle(a,-1);
    for(int i=0;i<=N+M;i++)
        printf("%d ",(int)(a[i].x/limit+0.5));
    return 0;
 }


快速幂


 ll poww(ll n,ll m)
{
    ll ans = 1;
    while(m > 0)
    {
        if(m & 1)ans = (ans * n) % mod;
        m = m >> 1;
        n = (n * n) % mod;
    }
    return ans;
} 

归并排序/逆序数对数

逆序对的定义:在一个序列a中,如果iaj 那么aiaj就是一个逆序对。
或可以求冒泡排序
交换次数

#include
#include
#include
int a[1000007]; 
int n,i,k,x,y;
long long flag=0;
void inv_get(int a[],int len)
{
	if(len<=1) return;
	int mid=(len/2);
	inv_get(a,mid);
	inv_get(a+mid,len-mid);
	int *b=(int *)malloc((n+3)*sizeof(int));
   	memcpy(b,a,len*sizeof(int));
   	int i1,i2,i;
   	for(i=0,i1=0,i2=mid;i1<mid||i2<len;i++)
   	{
   		if(i2==len)
   		{
   			a[i]=b[i1];
   			i1++;
   			flag+=i2-mid;
		}
		else if(i1==mid)
		{
			a[i]=b[i2];
			i2++;
		}
		else if(b[i1]<=b[i2])
		{
			a[i]=b[i1];
			i1++;
			flag+=i2-mid;
		}
		else
		{
			a[i]=b[i2];
			i2++;
		}
	}
	free(b);
}
int main()
{
	scanf("%d",&n);
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	inv_get(a,n);
	printf("%lld\n",flag);
}

cqb分治+FFT算法

#include 
using namespace std;
typedef long long ll;
const int maxlogn=18;
const int maxn=(1<<maxlogn)|1;
const int G0=15311432;
const int kcz=998244353;
int n,rev[maxn];
ll G[2][24],f[maxn],g[maxn],a[maxn],b[maxn];
void gcd(ll a,ll b,ll &x,ll &y)
{
    if(!b) x=1,y=0;
    else gcd(b,a%b,y,x),y-=x*(a/b);
}
inline ll inv(ll a)
{
    ll x,y;
    gcd(a,kcz,x,y);
    return (x+kcz)%kcz;
}
inline void calcrev(int logn)
{
    register int i;
    rev[0]=0;
    for(i=1;i<(1<<logn);i++)
        rev[i]=(rev[i>>1]>>1)|((i&1)<<(logn-1));
}
inline void FFT(ll *a,int logn,int flag)
{
    register int i,j,k,mid;
    register ll t1,t2,t;
    for(i=0;i<(1<<logn);i++)
        if(rev[i]<i)
            swap(a[rev[i]],a[i]);
    for(i=1;i<=logn;i++)
        for(mid=1<<(i-1),j=0;j<(1<<logn);j+=1<<i)
            for(k=0,t=1;k<mid;k++,t=t*G[flag][i]%kcz)
            {
                t1=a[j|k],t2=t*a[j|k|mid];
                a[j|k]=(t1+t2)%kcz,a[j|k|mid]=(t1-t2)%kcz;
            }
}
void solve(int l,int r,int logn)
{
    if(logn<=0) return;
    if(l>=n) return;
    int mid=(l+r)>>1,i;
    ll t=inv(r-l);
    solve(l,mid,logn-1); // 计算左区间
    calcrev(logn);
    memset(a+(r-l)/2,0,sizeof(ll)*(r-l)/2); // 拷贝左区间
    memcpy(a,f+l,sizeof(ll)*(r-l)/2); // 填充0
    memcpy(b,g,sizeof(ll)*(r-l)); // 拷贝g
    FFT(a,logn,0),FFT(b,logn,0); // 卷积
    for(i=0;i<r-l;i++) a[i]=a[i]*b[i]%kcz;
    FFT(a,logn,1);
    for(i=0;i<r-l;i++) a[i]=a[i]*t%kcz;
    for(i=(r-l)/2;i<r-l;i++)
        f[l+i]=(f[l+i]+a[i])%kcz; // 把卷积后的右半段的数加到f数组后半段
    // 可能你会注意到,这个卷积是(r-l)/2的长度卷一个r-l的长度,而我卷积时最终结果当作r-l的长度来存,这会不会有影响?注意到超出部分是(r-l)/2左右,根据fft的实现,超出部分是会重新从0开始填的,所以只会影响结果的前半段,与后半段无关
    solve(mid,r,logn-1); // 计算右区间
}
int main()
{
    int logn,i;
    G[1][23]=inv(G[0][23]=G0);
    for(i=22;i>=0;i--)
    {
        G[0][i]=G[0][i+1]*G[0][i+1]%kcz;
        G[1][i]=G[1][i+1]*G[1][i+1]%kcz;
    }
    scanf("%d",&n);
    for(logn=0;(1<<logn)<n;logn++);
    for(i=1;i<n;i++) scanf("%lld",&g[i]);
    for(i=0;i<n;i++) f[i]=!i;
    solve(0,1<<logn,logn);
    for(i=0;i<n;i++)
        printf("%lld ",(f[i]+kcz)%kcz);
    printf("\n");
    return 0;
}

你可能感兴趣的:(算法板子-一些小问题)