算法打印2021-11-14

头文件

#include<bits/stdc++.h>
#define intn long long
#define ls(k) (k)<<1
#define inf 2147483647
#define re register
#define rs(k) (k)<<1|1
#define _0for(i, a) for(int i = 0; i < (a); ++i)
#define _1for(i, a) for(int i = 1; i <=(a); ++i)
#define lowbit(x) ((x)&(-x))
#define debug(x) \
(void)(cerr << "L" << __LINE__\
			<< " : " << #x << " = " \
			<< (x) << endl )

using namespace std;
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;
}
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f; 
const int ninf = 0xc0c0c0c0;
const int N = 100001;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
}

图论

拓扑排序

统计入度,入度为0入栈,递推并更新入度,入度为0入栈,栈空结束

	queue<int>q;
	int tot=0;
	for(int i=1;i<=numb;i++)
	{
		if(!ind[i])
		{
			q.push(i);
			dist[i]=p[i];
		}
	}
	while(!q.empty())
	{
		int k=q.front();q.pop();
		for(int i=0;i<g1[k].size();i++)
		{
			int v=g1[k][i];
			dist[v]=max(dist[v],dist[k]+p[v]);
			ind[v]--;
			if(ind[v]==0)q.push(v);
		}
	}

缩点与割点

缩点

void tarjan(int x)
{
	dfn[x]=low[x]=++num;
	ins[x]=1;
	st.push(x);

	for(int i=0;i<g[x].size();i++)
	{
		int q=g[x][i];
		if(dfn[q]==0)
		{
			tarjan(q);
			low[x]=min(low[q],low[x]);
		}
		else if(ins[q]==1)
		{
			low[x]=min(low[x],dfn[q]);
		}
	}
	if(dfn[x]==low[x])
	{
		numb++;
		int p;
		do
		{
			p=st.top();
			st.pop();
			bl[p]=numb;
			nums[numb]++;
			ins[p]=0;
		}
		while(x!=p);
	}
}

最短路

djs

#include<bits/stdc++.h>
#define re register
using namespace std;
struct edge
{
    int to,cost;
};
vector<edge>g[500005];//定义路径结构体
int n,m,s;
int dis[500005];
struct node//定义堆结构体
{
	//(如果看不懂)https://www.cnblogs.com/ZERO-/p/9347296.html
	int u,d;
	bool operator<(const node&rhs)const
	{
		return d>rhs.d;
	}
};
inline void djs()
{
	for(re int i=1;i<=n;i++)dis[i]=2147483647;
	dis[s]=0;
	priority_queue<node>Q;//初始化
	
	node a ={s,0};
	Q.push(a);//第一个node
	
	while(!Q.empty())
	{
		node fr=Q.top();Q.pop();
		int u=fr.u,d=fr.d;
		//取出并记录
		if(d!=dis[u])continue;//避免处理无用数据,也就是dis[u]已经更新,之前未更新数据直接出栈,比如有一组数据 2 5,但是后面又入栈一组数据2 3,则2 5是无用数据
		for(re int j=0;j<g[u].size();j++)
		{
			int tm=g[u][j].to;
			if(dis[u]+g[u][j].cost<dis[tm])
			{			 
            	dis[tm]=dis[u]+g[u][j].cost;
				Q.push((node){tm,dis[tm]});
			}
		}
	}
}
int main()
{
	cin>>n>>m>>s;
	int x;
	for (re int i=1;i<=m;i++)
	{
        edge tmp;
      	cin>>x>>tmp.to>>tmp.cost;
        g[x].push_back(tmp);   
    }
    djs();
 	for (re int i=1;i<=n;i++)
  	printf("%d ",dis[i]);    
	return 0;
}

spfa


struct edge
{
	int v,w;
};
vector<edge>g[10001];
int d[10001];
int times[10001];
bool vis[10001];
queue<int>q;
int n;
void spfa(int s)
{
	memset(vis,0,sizeof(vis));
	memset(d,inf,sizeof(d));
	memset(times,0,sizeof(times));
	while(!q.empty())q.pop();
	q.push(s);
	vis[s]=1;
	d[s]=0;
	times[s]=1;
	while(!q.empty())
	{
		int now=q.front();
		q.pop();
		vis[now]=0;
		for(int j=0;j<g[now].size();j++)
		{
			edge p=g[now][j];
			if(d[p.v]>d[now]+p.w)
			{
				d[p.v]=d[now]+p.w;
				times[p.v]++;
				debug(times[p.v]);
				if(times[p.v]>n)
				{
					puts("YES");
					return;
				}
				if(!vis[p.v])
				{
					q.push(p.v);
					vis[p.v]=1;;
				}
			}
		}
	}
	puts("NO");
}
main(void)
{
	int t=read(),m;
	for(re int i=1;i<=t;i++)
	{
		n=read();
		m=read();
		int u,v,w;
		for(re int j=1;j<=m;j++)
		{
			edge t;
			u=read(),v=read(),w=read();
			t.v=v;
			t.w=w;
			g[u].push_back(t);
			t.v=u;
			if(w>=0)g[v].push_back(t);
		}
		spfa(1);
		for(int j=1;j<=n;j++)
			g[j].clear();
	}
}

二叉树

已知前序中序

char c[100000];
int cnt;
int l;
string a,b; 
void ss(int l1,int r1,int l2,int r2)
{
	if(l1>r1||l2>r2)return ;
	cnt--;//不断地找根
	c[cnt]=b[l2];
	for(int i=l1;i<=r1;i++)
	{
		if(a[i]==b[l2])//中序中的根
		{
			int lr=r1-i;
			int ll=i-l1;
			ss(i+1,r1,l2+1+ll,r2);//搜右
			ss(l1,i-1,l2+1,r2-lr);//搜左	
		} 
	} 
}
main(void)
{
	cin>>a>>b;//a中,b前 
	l=cnt=a.length();
	ss(0,cnt-1,0,cnt-1);
	for(int i=0;i<l;i++)
	{
		cout<<c[i];
	}
}

已知前序后序求中序的可能

char a[10002],b[10002];
int main()
{
            scanf("%s%s",&a,&b);
            int len=strlen(a),ans=1;
            for(int i=0;i<=len-2;i++)
                     for(int j=0;j<=len-1;j++)
                              if(b[j]==a[i]&&b[j-1]==a[i+1]);
            cout<<(1<<(ans+1));
            return 0; 
}

并查集

食物链这道题是要求维护 x x x y y y y y y z z z z z z x x x的关系,那么我们将并查集扩大三倍,表示三个族群,则可以得到相互的关系 ( x , y ) (x,y) (x,y)同类, ( x , y + n ) (x,y+n) (x,y+n),x吃y, ( x + n , y + 2 n ) (x+n,y+2n) (x+n,y+2n),x吃y, ( x + 2 n , y ) (x+2n,y) (x+2n,y)x吃y
种类并查集


int f[150005];
int find(int x)
{
	if(f[x]==x)return x;
	f[x]=find(f[x]);
	return f[x];
}
void merge(int x,int y)
{
	int fx=find(x);
	int fy=find(y);
	f[fx]=fy;
}
main(void)
{
	int n,k,jia=0;
	int x,y,cmd;
	n=read();
	k=read();
	for(int i=1;i<=3*n;i++)f[i]=i;
	for(int i=1;i<=k;i++)
	{
		cmd=read();
		x=read();
		y=read();
		if(x>n||y>n)jia++;
		else if(cmd==2&&(x==y||find(x)==find(y)||find(y)==find(x+n)))jia++; //x、y是同类或者y吃x 不可以 
		else if(cmd==1&&(find(x)==find(y+n)||find(y)==find(x+n)))jia++;//x吃y或者y吃x 不可以 
		else
		{
			if(cmd==1)
			{
				merge(find(x),find(y));	
				merge(find(x+n),find(y+n));
				merge(find(x+2*n),find(y+2*n));
			}
			else
			{
				merge(find(x),find(y+n));
				merge(find(x+n),find(y+2*n));
				merge(find(x+2*n),find(y));
			}
		}
	}
	cout<<jia;
}

权值并查集


const int maxn=50010;
int f[maxn];
int rf[maxn];
//rex[x]是x与祖先f[x]的关系 
//0同类,1吃,2被吃
int find(int x)
{
	if(f[x]==x)return x;
	int t=f[x];
	f[x]=find(f[x]);
	rf[x]=(rf[x]+rf[t])%3;
	return f[x];
} 
void merge(int x,int y,int re)
{
	f[x]=y;//必须更新到祖先再使用这个函数,否则会顶掉原f[x] 
	rf[x]=re; 
}
main(void)
{
	int n,k,jia=0;
	n=read();
	k=read();
	_1for(i,n)f[i]=i;
	_1for(p,k)
	{
		int re,x,y;
		re=read();
	 	x=read();
		y=read();
		if(x>n||y>n)jia++;
		else if(re==2&&x==y)jia++;
		else if(find(x)==find(y))//已经有了关系
		{
			if(re-1!=(rf[x]-rf[y]+3)%3)jia++;//向量运算的思路 
		} 
		else
		{
			int newre=(re-1+rf[y]-rf[x]+3)%3;
			merge(find(x),find(y),newre);
		}
	}
	cout<<jia;
}

最小生成树

k算法

int f[1000];
int ans=0;
int ansm=0;
struct node
{
	int u,v,w;
}a[100005];
bool cmp(node a,node b)
{
	return a.w<b.w;
}
int find(int x)
{
	if(f[x]==x)return x;
	return f[x]=find(f[x]);
}
main(void)
{
	int n,m;
	cin>>n>>m;
	_1for(i,n)f[i]=i;
	_1for(i,m)
	{
		cin>>a[i].u>>a[i].v>>a[i].w;
	}
	sort(a+1,a+1+m,cmp);
	int cnt=0;
	_1for(i,m)
	{
		if(cnt==n-1)break; 
		int x=find(a[i].u);
		int y=find(a[i].v);
		if(x!=y)
		{
			f[x]=y;
			ans+=a[i].w;
		
			cnt++;
			ansm=max(ansm,a[i].w);
		}
	}
	cout<<n-1<<" "<<ansm;	
}




p算法

const int inf=999999;
int mp[400][400];
int n;
int visit[400];
int dist[400];
int ans=0;
int prime(int cur)
{
	int index;
	int sum=0;
	visit[cur]=1;
	_1for(i,n)dist[i]=mp[cur][i];
	for(int i=1;i<=n-1;i++)
	{
		int mincost=inf;
		_1for(j,n)
		{
			if(!visit[j]&&dist[j]<mincost)
			{
				mincost=dist[j];
				index=j;
			}
		}
		debug(index);
		visit[index]=1;
		sum+=mincost;
		ans=max(ans,mincost);
		_1for(j,n)
		{
			if(!visit[j]&&dist[j]>mp[index][j])
			{
				dist[j]=mp[index][j];
			}
		}
	}
	return sum;
}
main(void)
{
	int m,x,y,z;
	cin>>n>>m;
	_1for(i,n)
	_1for(j,n)
	mp[i][j]=inf;
	_1for(i,m)
	{
		cin>>x>>y>>z;
		mp[x][y]=z;
		mp[y][x]=z; 
	}
	prime(1);
	cout<<n-1<<" "<<ans;
}




最大二分图匹配

给定一个二分图,其左部点的个数为 n,右部点的个数为 m,边数为 e,求其最大匹配的边数。
左部点从 1 至 n 编号,右部点从 1 至 m 编号。


const int maxn=1005;
int n,m,t;
int mch[maxn],vis[maxn];
vector<int >g[maxn];
bool dfs(int u,int tag)
{
	if(vis[u]==tag)return false;//应该是避免绕圈 
	vis[u]=tag;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(mch[v]==0||dfs(mch[v],tag))//如果这个点未被匹配或者原先匹配的点可以找到别的匹配点 
		{
			mch[v]=u;
			return true;
		}
	}
	return false;
}
main(void)
{
	n=read();
	m=read();
	t=read();
	while(t--)
	{
		int u=read();
		int v=read();
		g[u].push_back(v);
	} 
	int ans=0;
	for(int i=1;i<=n;i++)
	{
		if(dfs(i,i))
		{
			ans++;
		}
	}
	cout<<ans;
}

数论

积性函数指对于所有互质的整数a和b有性质f(ab)=f(a)f(b)的数论函数。

狄利克雷卷积

( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f * g)(n)=\sum_{d \mid n} f(d) g\left(\frac{n}{d}\right) (fg)(n)=dnf(d)g(dn)
性质1:

两个积性函数的狄利克雷卷积还是积性函数。

证明:感性理解一下,两个互质的下标乘起来,相当于两个和式乘起来,因为是互质的相当于枚举到了乘积的所有约数,因为和式里面都是积性函数所以乘起来也是积性函数。

性质2:

三大运算规律:结合律,交换律,分配律。

常见运算

除数函数: σ x ( n ) = ∑ d ∣ n d x \sigma_{x}(n)=\sum_{d \mid n} d^{x} σx(n)=dndx
约数个数函数: d ( n ) = ∑ d ∣ n 1 d(n)=\sum_{d \mid n} 1 d(n)=dn1 约数和函数: σ ( n ) = ∑ d n d \sigma(n)=\sum_{d n} d σ(n)=dnd
元函数: e ( n ) = [ n = 1 ] ( { 1 , 0 , 0 , 0 , 0 … . . . } ) e(n)=[n=1](\{1,0,0,0,0 \ldots . . .\}) e(n)=[n=1]({1,0,0,0,0...})
恒等函数: I ( n ) = 1 ( { 1 , 1 , 1 , 1 , 1 … … } ) I(n)=1(\{1,1,1,1,1 \ldots \ldots\}) I(n)=1({1,1,1,1,1})
单位函数: ε ( n ) = n ( { 1 , 2 , 3 , 4 , 5 … … } ) \varepsilon(n)=n(\{1,2,3,4,5 \ldots \ldots\}) ε(n)=n({1,2,3,4,5})
欧拉函数: ϕ ( n ) \phi(n) ϕ(n) 莫比乌斯函数: μ ( n ) \mu(n) μ(n)

μ ( i ) = { 1 , i = 1 ( − 1 ) k , i = p 1 ∗ p 2 ∗ … ∗ p k 0 ,  rest  \mu(i)=\left\{\begin{array}{c}1, i=1 \\ (-1)^{k}, i=p 1 * p 2 * \ldots * p k \\ 0, \text { rest }\end{array}\right. μ(i)=1,i=1(1)k,i=p1p2pk0, rest 

ε = ϕ ∗ I ⇔ n = ∑ d ∣ n ϕ ( d ) \varepsilon=\phi * I \Leftrightarrow n=\sum_{d \mid n} \phi(d) ε=ϕIn=dnϕ(d)
d = I ∗ I ⇔ d ( n ) = ∑ d ∣ n 1 d=I * I \Leftrightarrow d(n)=\sum_{d \mid n} 1 d=IId(n)=dn1
σ = ε ∗ I ⇔ σ ( n ) = ∑ d ∣ n d \sigma=\varepsilon * I \Leftrightarrow \sigma(n)=\sum_{d \mid n} d σ=εIσ(n)=dnd
e = I ∗ μ ⇔ [ n = = 1 ] = ∑ d ∣ n μ ( d ) e=I * \mu \Leftrightarrow[n==1]=\sum_{d \mid n} \mu(d) e=Iμ[n==1]=dnμ(d)
ϕ = ε ∗ μ ⇔ ϕ ( n ) ∑ d ∣ n μ ( d ) ∗ n d \phi=\varepsilon * \mu \Leftrightarrow \phi(n) \sum_{d \mid n} \mu(d) * \frac{n}{d} ϕ=εμϕ(n)dnμ(d)dn

莫比乌斯反演


g ( n ) = ∑ d ∣ n f ( d ) g(n)=\sum_{d \mid n} f(d) g(n)=dnf(d)

f ( n ) = ∑ d ∣ n μ ( d ) g ( n d ) f(n)=\sum_{d |n} \mu(d) g\left(\frac{n}{d}\right) f(n)=dnμ(d)g(dn)
证明:这里需要用到前面提到的性质: μ ∗ I = ϵ \mu * I=\epsilon μI=ϵ
给出的条件等价于 g = f ∗ I g=f * I g=fI
所以 g ∗ μ = f ∗ I ∗ μ = f ∗ ϵ = f g * \mu=f * I * \mu=f * \epsilon=f gμ=fIμ=fϵ=f g ∗ μ = f g * \mu=f gμ=f 即 结论

杜教筛

g ( 1 ) S ( n ) = ∑ i = 1 n ( f ∗ g ) ( i ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) g(1) S(n)=\sum_{i=1}^{n}(f * g)(i)-\sum_{i=2}^{n} g(i) S\left(\left\lfloor\frac{n}{i}\right\rfloor\right) g(1)S(n)=i=1n(fg)(i)i=2ng(i)S(in)
求解 S ( n ) S(n) S(n),可以设定 f f f g g g
( 1 ) μ ( n ) (1)\mu(n) (1)μ(n)前缀和
考虑到莫比乌斯函数的性质 μ ∗ I = ϵ , \mu * I=\epsilon, μI=ϵ, 自然想到取 f = μ , g = I , f ∗ g = ϵ f=\mu, g=I, f * g=\epsilon f=μ,g=I,fg=ϵ

( 2 ) φ (2)\varphi (2)φ 的前缀和
考虑到 φ \varphi φ 的性质 φ ∗ I = i d , \varphi * I=i d, φI=id, f = φ , g = I , f ∗ g = i d f=\varphi, g=I, f * g=i d f=φ,g=I,fg=id

(3) ∑ i = 1 n φ ( i ) ⋅ i \sum_{i=1}^{n} \varphi(i) \cdot i i=1nφ(i)i
f = φ ⋅ i d , g = i d , f=\varphi \cdot i d, g=i d, f=φid,g=id, 考虑迪利克雷卷积的形式得到 ( f ∗ g ) ( n ) = ∑ d ∣ n ( φ ( d ) ⋅ d ) ⋅ ( n d ) = (f * g)(n)=\sum_{d \mid n}(\varphi(d) \cdot d) \cdot\left(\frac{n}{d}\right)= (fg)(n)=dn(φ(d)d)(dn)=
n ∑ d ∣ n φ ( d ) = n 2 n \sum_{d \mid n} \varphi(d)=n^{2} ndnφ(d)=n2
( f ∗ g ) ( i ) = i 2 (f * g)(i)=i^{2} (fg)(i)=i2
这样就可以快速求得 ( f ∗ g ) ( i ) (f * g)(i) (fg)(i) 的前缀和 n ( n + 1 ) ( 2 n + 1 ) 6 \frac{n(n+1)(2 n+1)}{6} 6n(n+1)(2n+1)

例题

const int N=1000009;
const int mod=1e9+7;
int pre[N];
int phi[N];
int vis[N];
int prime[N];
int _2,_6;
unordered_map<int,int>mp;
void init()
{
	phi[1]=1;
	int cnt=0;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1;j<=cnt&&prime[j]*i<=N;j++)
		{
			vis[prime[j]*i]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;	
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
		}
	}
} 
int getsum(int n)
{
	if(n<=N)return pre[n];
	if(mp.count(n))return mp[n];
	int res=n*(n+1)%mod*(2*n+1)%mod*_6%mod;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		res-=(l+r)*(r-l+1)/2%mod*getsum(n/l)%mod; 
	}
	return mp[n]=res%mod;
}
int qpow(int a,int b,int mod)
{
	if(b==0)return 1;
	if(b%2==0)
	{
		int temp=qpow(a,b/2,mod)%mod;
		return temp*temp%mod;
	}
	else
	{
		return qpow(a,b-1,mod)*a%mod;
	}
}
main(void)
{
	init();
	for(int i=1;i<=N;i++)
	{
		pre[i]=(pre[i-1]+i*phi[i])%mod;
	}
	int t=read();
	_2=qpow(2,mod-2,mod);//2乘法逆元
	_6=qpow(6,mod-2,mod);//6乘法逆元 
	while(t--)
	{
		int n=read();
		int a=read();
		int b=read();
		printf("%lld\n",(getsum(n)-1+mod)%mod*_2%mod);
	}
	
}

min_25筛

求2-n质数之和


#include <bits/stdc++.h>
#define int long long
#define LL long long
using namespace std;

const int N = 6000010;

int prime[N], id1[N], id2[N], flag[N], ncnt, m;
LL g[N], sum[N], a[N], T,n;
namespace Min25 {
    inline int ID(LL x) {
        return x <= T ? id1[x] : id2[n / x];
    }

    inline LL calc(LL x) {
        return x * (x + 1) / 2 - 1;
    }

    inline LL f(LL x) {
        return x;
    }

    inline void init() {
        T = sqrt(n + 0.5);
        for (int i = 2; i <= T; i++) {
            if (!flag[i]) prime[++ncnt] = i, sum[ncnt] = sum[ncnt - 1] + i;
            for (int j = 1; j <= ncnt && i * prime[j] <= T; j++) {
                flag[i * prime[j]] = 1;
                if (i % prime[j] == 0) break;
            }
        }
        for (LL l = 1; l <= n; l = n / (n / l) + 1) {
            a[++m] = n / l;
            if (a[m] <= T) id1[a[m]] = m; else id2[n / a[m]] = m;
            g[m] = calc(a[m]);
        }
        for (int i = 1; i <= ncnt; i++) 
            for (int j = 1; j <= m && (LL)prime[i] * prime[i] <= a[j]; j++) 
                g[j] = g[j] - (LL)prime[i] * (g[ID(a[j] / prime[i])] - sum[i - 1]);
    }

    inline LL solve(LL x) {
        if (x <= 1) return x;
        return n = x, init(), g[ID(n)];
    }

}

main(void) {
	LL t;scanf("%lld",&t);
	while(t--)
	{
		memset(prime,0,sizeof(prime));
		memset(prime,0,sizeof(prime));
		
		memset(id1,0,sizeof(prime));
		
		memset(id2,0,sizeof(prime));
		
		memset(flag,0,sizeof(prime));
		
		memset(g,0,sizeof(g));
		
		memset(sum,0,sizeof(g));
	    
		memset(a,0,sizeof(g));
		ncnt=0;
		m=0;
		T=0;
		n=0;
	 	scanf("%lld", &n);
		
	    LL mod;scanf("%lld",&mod);
	    printf("%lld\n", (Min25::solve(n+1)-2+(3+n+1)*(n-1)/2));
	    printf("%lld\n", Min25::solve(n));
	}
}

矩阵快速幂求数列

矩阵快速幂可以在很短的时间内完成矩阵的运算,在求数列的某一项时有很好的作用。举例:斐波那契数列 a [ 1 ] = 1 a[1]=1 a[1]=1, a [ 2 ] = 1 a[2]=1 a[2]=1,从第三项开始, a [ n ] = a [ n − 1 ] + a [ n − 2 ] a[n]=a[n-1]+a[n-2] a[n]=a[n1]+a[n2]
可以得到式子
( a [ n ] a [ n − 1 ] ) = ( 1 1 1 0 ) ( a [ n − 1 ] a [ n − 2 ] ) \left( \begin{array}{c} a\left[ n \right]\\ a\left[ n-1 \right]\\ \end{array} \right) =\left( \begin{matrix} 1& 1\\ 1& 0\\ \end{matrix} \right) \left( \begin{array}{c} a\left[ n-1 \right]\\ a\left[ n-2 \right]\\ \end{array} \right) (a[n]a[n1])=(1110)(a[n1]a[n2])
( a [ n ] a [ n − 1 ] ) = ( 1 1 1 0 ) n − 2 ( a [ 2 ] a [ 1 ] )     n ≥ 3 \left( \begin{array}{c} a\left[ n \right]\\ a\left[ n-1 \right]\\ \end{array} \right) =\left( \begin{matrix} 1& 1\\ 1& 0\\ \end{matrix} \right) ^{n-2}\left( \begin{array}{c} a\left[ 2 \right]\\ a\left[ 1 \right]\\ \end{array} \right) \ \ \ n\ge 3 (a[n]a[n1])=(1110)n2(a[2]a[1])   n3
下面考虑变式的情况, a [ 1 ] = a a[1]=a a[1]=a, a [ 2 ] = b a[2]=b a[2]=b, a [ n ] = 2 ∗ a [ n − 1 ] + a [ n − 2 ] + n 3 a[n]=2*a[n-1]+a[n-2]+n^3 a[n]=2a[n1]+a[n2]+n3 , 当 n > 2 n>2 n>2

i 4 = i 4 + 4 n 3 + 6 n 2 + 4 n + 1 ; i^4=i^4+4n^3+6n^2+4n+1; i4=i4+4n3+6n2+4n+1;
( a [ n ] a [ n + 1 ] ( n + 1 ) 4 ( n + 1 ) 3 ( n + 1 ) 2 ( n + 1 ) 1 ) = ( 0 1 0 0 0 0 0 2 1 1 4 6 4 1 0 0 1 4 6 4 1 0 0 0 1 3 3 1 0 0 0 0 1 2 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) ( a [ n − 1 ] a [ n ] n 4 n 3 n 2 n 1 ) \left( \begin{array}{l} a\left[ n \right]\\ a\left[ n+1 \right]\\ \left( n+1 \right) ^4\\ \left( n+1 \right) ^3\\ \left( n+1 \right) ^2\\ \left( n+1 \right)\\ 1\\ \end{array} \right) =\left( \begin{matrix} 0& 1& 0& 0& 0& 0& 0\\ 2& 1& 1& 4& 6& 4& 1\\ 0& 0& 1& 4& 6& 4& 1\\ 0& 0& 0& 1& 3& 3& 1\\ 0& 0& 0& 0& 1& 2& 1\\ 0& 0& 0& 0& 0& 1& 1\\ 0& 0& 0& 0& 0& 0& 1\\ \end{matrix} \right) \left( \begin{array}{l} a\left[ n-1 \right]\\ a\left[ n \right]\\ n^4\\ n^3\\ n^2\\ n\\ 1\\ \end{array} \right) a[n]a[n+1](n+1)4(n+1)3(n+1)2(n+1)1=0200000110000001100000441000066310004432100111111a[n1]a[n]n4n3n2n1
( a [ n ] a [ n + 1 ] ( n + 1 ) 4 ( n + 1 ) 3 ( n + 1 ) 2 ( n + 1 ) 1 ) = ( 0 1 0 0 0 0 0 2 1 1 4 6 4 1 0 0 1 4 6 4 1 0 0 0 1 3 3 1 0 0 0 0 1 2 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 ) n − 1 ( a [ 1 ] a [ 2 ] 1 6 8 4 2 1 ) \left( \begin{array}{l} a\left[ n \right]\\ a\left[ n+1 \right]\\ \left( n+1 \right) ^4\\ \left( n+1 \right) ^3\\ \left( n+1 \right) ^2\\ \left( n+1 \right)\\ 1\\ \end{array} \right) =\left( \begin{matrix} 0& 1& 0& 0& 0& 0& 0\\ 2& 1& 1& 4& 6& 4& 1\\ 0& 0& 1& 4& 6& 4& 1\\ 0& 0& 0& 1& 3& 3& 1\\ 0& 0& 0& 0& 1& 2& 1\\ 0& 0& 0& 0& 0& 1& 1\\ 0& 0& 0& 0& 0& 0& 1\\ \end{matrix} \right) ^{n-1}\left( \begin{array}{l} a\left[ 1 \right]\\ a\left[ 2 \right]\\ 16^{}\\ 8^{}\\ 4\\ 2\\ 1\\ \end{array} \right) a[n]a[n+1](n+1)4(n+1)3(n+1)2(n+1)1=0200000110000001100000441000066310004432100111111n1a[1]a[2]168421


const int mod=2147493647;
struct node
{
	int m[10][10];
};
node mul(node a,node b)
{
	node ans;
	memset(ans.m,0,sizeof(ans.m));
	for(int i=1;i<=7;i++)
	for(int j=1;j<=7;j++)
	{
		for(int k=1;k<=7;k++)
		{
			ans.m[i][j]=(ans.m[i][j]+a.m[i][k]*b.m[k][j]%mod)%mod;
		}
	}
	return ans;
} 
node ksm(node a,int b)
{
	node res;//单位向量 
	memset(res.m,0,sizeof(res.m));
	for(int i=1;i<=7;i++)
	res.m[i][i]=1;
	if(b==0)return res;
	if(b%2==0)
	{
		node temp=ksm(a,b/2);
		return mul(temp,temp);
	}
	else
	{
		return mul(a,ksm(a,b-1));
	}
}
main(void)
{
	int t=read();
	while(t--)
	{
		int n=read();
		node a;
		memset(a.m,0,sizeof(a.m));
		int b[10][10];
		b[1][1]=read();
		b[2][1]=read();
		b[3][1]=16;
		b[4][1]=8;
		b[5][1]=4;
		b[6][1]=2;
		b[7][1]=1;
		a.m[1][2]=1;
		a.m[2][1]=2,a.m[2][2]=1,a.m[2][3]=1,a.m[2][4]=4,a.m[2][5]=6,a.m[2][6]=4,a.m[2][7]=1;
								a.m[3][3]=1,a.m[3][4]=4,a.m[3][5]=6,a.m[3][6]=4,a.m[3][7]=1;																	
											a.m[4][4]=1,a.m[4][5]=3,a.m[4][6]=3,a.m[4][7]=1;
														a.m[5][5]=1,a.m[5][6]=2;a.m[5][7]=1;	
																	a.m[6][6]=1,a.m[6][7]=1; 
																				a.m[7][7]=1;
		if(n==1)
		{
			printf("%lld\n",b[1][1]%mod);
		}
		else if(n==2)
		{
			printf("%lld\n",b[2][1]%mod);
		}
		else
		{	
			node index=ksm(a,n-1);
			int ans=0;
			for(int i=1;i<=7;i++)
			ans+=index.m[1][i]*b[i][1];
			printf("%lld\n",ans%mod);
			/* 
			for(int i=1;i<=7;i++)
            {
            	for(int j=1;j<=7;j++)
            	{
            		printf("%lld ",index.m[i][j]);
				}
				printf("\n");
			}
			*/ 
		}
	}
}

乘法逆元

费马小定理

递推公式
因为
⌊ p i ⌋ ∗ i = p − p   m o d   i \lfloor\frac{p}{i}\rfloor*i=p-p\ mod\ i ipi=pp mod i

⌊ p i ⌋ ∗ i = − p   m o d   i \lfloor\frac{p}{i}\rfloor*i=-p\ mod\ i ipi=p mod i
因此
i − 1 = ( − p   m o d   i ) − 1 ∗ ⌊ p i ⌋ i^{-1}=(-p\ mod\ i)^{-1}*\lfloor\frac{p}{i}\rfloor i1=(p mod i)1ip

int ans[1000]={0,1};
main(void)
{
	int n,p;
 	cin>>n>>p;
 	printf("1\n");
 	for(int i=2;i<=n;i++)
 	{
 		ans[i]=(p-(p/i))*ans[p%i]%p;
 	}
 	cout<<ans[666]<<endl;
}

扩展欧几里得

( a , b ) = a x + b y (a,b)=ax+by (a,b)=ax+by

int exgcd(int a, int b, int& x, int& y) {
    if(a < b) return exgcd(b, a, y, x);
    if(b == 0) {
        x = 1; y = 0;
        return a;
    } else {
        int x1;
        int d = exgcd(b, a % b, x1, x);
        y = x1 - a / b * x;
        return d;
    }
}

大数

高精度加

string add(string str1,string str2)
{
	string str;
	int len1=str1.length();
	int len2=str2.length();//得到长度
	
	if(len1<len2)//短的补0
	{
		for(int i=1;i<=len2-len1;i++)
			str1="0"+str1;
	}
	else
	{
		for(int i=1;i<=len1-len2;i++)
			str2="0"+str2;
	}
	len1=str1.length();
	int cf=0;
	int temp;
	for(int i=len1-1;i>=0;i--)//从第一位开始相加
	{
		temp=str1[i]-'0'+str2[i]-'0'+cf;
		cf=temp/10;//储存进位
		temp%=10;//储存当前位
		str=char(temp+'0')+str;//构造答案str
	}
	if(cf!=0)str=char(cf+'0')+str;
	return str;
}

高精减

string add(string str1,string str2)
{
	string str;
	int len1=str1.length();
	int len2=str2.length();//得到长度
	
	if(len1<len2)//短的补0
	{
		for(int i=1;i<=len2-len1;i++)
			str1="0"+str1;
	}
	else
	{
		for(int i=1;i<=len1-len2;i++)
			str2="0"+str2;
	}
	len1=str1.length();
	int cf=0;
	int temp;
	for(int i=len1-1;i>=0;i--)//从第一位开始相加
	{
		temp=str1[i]-'0'+str2[i]-'0'+cf;
		cf=temp/10;//储存进位
		temp%=10;//储存当前位
		str=char(temp+'0')+str;//构造答案str
	}
	if(cf!=0)str=char(cf+'0')+str;
	return str;
}

a a a m m m 互质时, a φ ( m ) ≡ 1   m o d   m a^{\varphi(m)} \equiv 1 \quad \bmod m aφ(m)1modm
φ ( x ) = x ∏ i = 1 n ( 1 − 1 p i ) \varphi(x)=x \prod_{i=1}^{n}\left(1-\frac{1}{p_{i}}\right) φ(x)=xi=1n(1pi1)
a b   m o d   m a^{b} \ mod \ m ab mod m
b ≥ φ ( m ) b \geq \varphi(m) bφ(m) , a b ≡ a ( b   m o d   φ ( m ) ) + φ ( m )   m o d   m , a^{b} \equiv a^{(b \bmod \varphi(m))+\varphi(m)} \bmod m ,aba(bmodφ(m))+φ(m)modm

string s;
int m;
int qpow(int a,int n)
{
	if(n==0)return 1;
	else if(n%2==1)
	return qpow(a,n-1)*a%m;
	else
	{
		int temp=qpow(a,n/2)%m;
		return temp*temp%m;
	}
}
int phi(int n)
{
	int ans=n;
	for(int i=2;i<=sqrt(n);i++)
	{
		if(n%i==0)
		{
			ans=ans/i*(i-1);//这是一个p,注意先除再乘,防止炸int
			while(n%i==0) n/=i; //把质数次方因子筛没了,就不会错了
		}
	}
	if(n>=2) ans=ans/n*(n-1);//最后有可能剩下
	return ans;
}
main(void)
{
	int a;
	cin>>a>>m>>s;
	int l=s.size();
	int b=0;
	int flag=0;
	int ph=phi(m);
//	debug(ph);
	for(int i=0;i<l;i++)
	{
		b=b*10+s[i]-'0';
		if(b>=ph)
		{
			flag=1;
			b%=ph;
		}
//		debug(b);
	}
	if(flag)
	{
		b+=ph;
	}
	int ans=1;
	cout<<qpow(a,b);
}

阶乘预处理与快速幂

阶乘预处理

void init(){
    int i;
    fac[0]=1;
    inv[0]=1;
    fac[1]=1;
    inv[1]=1;
    for (i=2;i<50010;i++){
        fac[i]=((fac[i-1]*i)%inf+inf)%inf;
        inv[i]=(qpow(fac[i],inf-2)+inf)%inf;
    }
}

阶乘
C n m = n ! m ! ( n − m ) ! C_{n}^{m}=\frac{n!}{m!\left( n-m \right) !} Cnm=m!(nm)!n!

int C(int n,int m){
    if (n<m||m<0) return 0;
    return  (fac[n]*inv[m]%inf*inv[n-m]%inf+inf)%inf;
}

搜索

一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。约翰想弄清楚他的田地已经形成了多少水坑。给出约翰田地的示意图,确定当中有多少水坑。

inline void bfs(int a,int b)
{
	queue<node>q;
	node t;
	t.x=a;t.y=b;
	q.push(t);
	flag[a][b]=cnt;//标记
	while(!q.empty())
	{
		t=q.front();
		q.pop();
	//	debug(ans);
		for(int i=1;i<=8;i++)
		{
			int nx=t.x+xx[i];	
			int ny=t.y+yy[i];
			if(nx<1||ny<1||nx>n||ny>m||flag[nx][ny]!=0||ma[nx][ny]!='W')
			{
				continue;
			}
			flag[nx][ny]=cnt;
			node next;
			next.x=nx;
			next.y=ny;
			q.push(next);
		}	
	} 
	
} 

void dfs(int xx,int yy)
{
	if(xx>n||yy>m||xx<1||yy<1)return;
	if(a[xx][yy]!=1)return;
	
	a[xx][yy]=ans;
	for(int i=1;i<=8;i++)
	if(vis[xx+x[i]][yy+y[i]]==0)
	{
		vis[xx+x[i]][yy+y[i]]=1; 
		dfs(xx+x[i],yy+y[i]);
		vis[xx+x[i]][yy+y[i]]=0;
	}
}

dp

树状dp

直系上司不能与下属同去。

int dp[6005][2];//dp[i][0]是不要i的最值,dp[i][1]是要i的最值
vector<int >g[6005];
int a[6005];
int m[6005];
int find(int now,int pre)
{
	int fa,son;
	int len=g[now].size();
	dp[now][1]=a[now];
	dp[now][0]=0;
	for(int i=0;i<len;i++)
	{
		if(g[now][i]==pre)continue;//避免重复
		son=find(g[now][i],now);//得到儿子的dp值,儿子其实是g[now][i],没有return也可以
		dp[now][1]+=dp[son][0];
		dp[now][0]+=max(dp[son][0],dp[son][1]);
	}	
	return now;
}
main(void)
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	int x,y;
	for(int i=1;i<=n-1;i++)
	{
		cin>>y>>x;
		g[x].push_back(y);//双向建边,但是要注意不能往复遍历,因此函数要记录上一个的遍历
		g[y].push_back(x);
	}
	int f=find(1,0);//从1开始遍历
	printf("%d",max(dp[f][0],dp[f][1]));//因为dp[f][]是最后遍历的(先是儿子),所以输出这个即可
}

状压dp

农场主John新买了一块长方形的新牧场,这块牧场被划分成M行N列,有些土地相当贫瘠,不能用来种草。并且,奶牛们喜欢独占一块草地的感觉,于是John不会选择两块相邻的土地。
John想知道,一共有多少种种植方案可供他选择?(当然,把新牧场完全荒废也是一种方案)


const int p=100000000;
int m,n,a[20];
int dp[20][1000000];
main(void)
{
	int m=read();
	int n=read();
	for(int i=1;i<=m;i++)
	for(int j=1;j<=n;j++)
	{
		int x=read();
		a[i]=(a[i]<<1)+!x;//初始要求 
	}
	//(1<<12)-1
	for(int i=1;i<=m;i++)//第几行 
	{
		for(int s=0;s<=(1<<n)-1;s++)//这一行的状态合适吗 
		{
			if(s&a[i]||s&(s<<1))continue;
			if(i==1)dp[i][s]=1;//存储行数与状态下的方案数
			for(int s1=0;s1<=(1<<n)-1;s1++)//枚举上一个状态 
			{
				if(s1&a[i-1]||s1&(s1<<1))continue;
				if(s1&s)continue;
				(dp[i][s]+=dp[i-1][s1]%p)%=p;
			} 
		} 
	}
	int ans=0;
	for(int s=0;s<=(1<<n)-1;s++)
	{
		(ans+=dp[m][s]%p)%=p;
	}
	cout<<ans%p;
	//失败的情况    
	//  0 
	//  1 
}

线段树

维护区间加法和乘法


const int maxn=200010;
int p,a[maxn],sum[4*maxn],mul[4*maxn],add[4*maxn];
inline void qm1(int k)
{
	
	sum[ls(k)]%=p;
	mul[ls(k)]%=p;
	add[ls(k)]%=p;
	
	sum[rs(k)]%=p;
	mul[rs(k)]%=p;
	add[rs(k)]%=p;
}
inline void build(int k,int l,int r)
{
	mul[k]=1;
	if(l==r)
	{
		sum[k]=a[l];
		return ;
	}
	int mid=(l+r)/2;
	build(ls(k),l,mid);
	build(rs(k),mid+1,r);
	sum[k]=sum[ls(k)]+sum[rs(k)];
}
inline void pushdown(int k,int l,int r)
{
	int mid=(l+r)/2;
	sum[ls(k)]*=mul[k];
	sum[rs(k)]*=mul[k];
	
	sum[ls(k)]+=add[k]*(mid-l+1);
	sum[rs(k)]+=add[k]*(r-mid);
	
	mul[ls(k)]*=mul[k];
	mul[rs(k)]*=mul[k];
	
	add[rs(k)]=add[rs(k)]*mul[k]+add[k];
	add[ls(k)]=add[ls(k)]*mul[k]+add[k];
	qm1(k);
	add[k]=0;
	mul[k]=1;
}
inline void ADD(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&y>=r)
	{
		add[k]+=v;
		sum[k]+=v*(r-l+1);
		qm1(k);
		return ;
	}

	pushdown(k,l,r);
	int mid=(l+r)/2;
	if(x<=mid)ADD(ls(k),l,mid,x,y,v);
	if(y>mid)ADD(rs(k),mid+1,r,x,y,v);
	sum[k]=sum[ls(k)]+sum[rs(k)]; 

}
inline void MUL(int k,int l,int r,int x,int y,int v)
{
	if(x<=l&&y>=r)
	{
		add[k]*=v;//规定的规则是先加后乘,想要表示先乘后加必须要把加法标记更新 
		mul[k]*=v;
		sum[k]*=v;
		qm1(k);
		return ;
	}
	pushdown(k,l,r);
	int mid=(l+r)/2;
	if(x<=mid)MUL(ls(k),l,mid,x,y,v);
	if(y>mid)MUL(rs(k),mid+1,r,x,y,v);
	sum[k]=sum[ls(k)]+sum[rs(k)];
}
inline int check(int k,int l,int r,int x,int y)
{
	if(x<=l&&y>=r)return sum[k];
	pushdown(k,l,r);
	int mid=(l+r)/2;
	int ans=0;
	if(x<=mid)ans+=check(ls(k),l,mid,x,y);

	if(y>mid)ans+=check(rs(k),mid+1,r,x,y);
	return ans%p; 
}
main(void)
{
	int n,m,cmd,x,y,k;
	scanf("%lld%lld%lld",&n,&m,&p);
	_1for(i,n)
	{
		scanf("%lld",&a[i]);
	}
	build(1,1,n);
	_1for(j,m)
	{
		scanf("%lld%lld%lld",&cmd,&x,&y);
		if(cmd==1)
		{
			scanf("%lld",&k);
			MUL(1,1,n,x,y,k);
		}
		if(cmd==2)
		{
			scanf("%lld",&k);
			ADD(1,1,n,x,y,k);
		}
		if(cmd==3)
		{
			printf("%lld\n",check(1,1,n,x,y)%p);
		}
	}
}

lca与树剖

dfs

void dfs1(int u)//预处理siz son dep fa
{
	siz[u]=1;//包含u的子树
	son[u]=0;
	for(int i=0;i<g[u].size();i++)
	{
		int v=g[u][i];
		if(v==fa[u])continue;
		
		dep[v]=dep[u]+1;//更新子节点
		fa[v]=u;
		
		dfs1(v);
		siz[u]+=siz[v];//更新v后,累加到u
		if(siz[v]>siz[son[u]])son[u]=v;//更新重儿子
	}
}
void dfs2(int u,int rt)//预处理id top rk  
{
	id[u]=++cnt;
	//rk[index]=u;
	wt[cnt]=w[u];
	top[u]=rt;
	if(son[u])dfs2(son[u],rt);//先搜重儿子
	for(int i=0;i<g[u].size();i++) 
	{
		int v=g[u][i];
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}

维护树链
预处理过后要对链进行维护,因为每段链是连续的,一般选择线段树维护区间和,实现区间查询和区间更新,即将得到的 i d [ ] id[] id[] w t [ ] wt[] wt[]进行建树

inline int qRange(int x,int y){
	int ans=0;
	while(top[x]!=top[y]){//当两个点不在同一条链上 
		if(dep[top[x]]<dep[top[y]])swap(x,y);//把x点改为所在链顶端的深度更深的那个点
		res=0;
		query(1,1,n,id[top[x]],id[x]);//ans加上x点到x所在链顶端 这一段区间的点权和
		ans+=res;
		ans%=mod;//按题意取模 
		x=fa[top[x]];//把x跳到x所在链顶端的那个点的上面一个点
	}
	//直到两个点处于一条链上
	if(dep[x]>dep[y])swap(x,y);//把x点深度更深的那个点
	res=0;
	query(1,1,n,id[x],id[y]);//这时再加上此时两个点的区间和即可
	ans+=res;
	return ans%mod;
}

inline void updRange(int x,int y,int k){//同上 
	k%=mod;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]])swap(x,y);
		update(1,1,n,id[top[x]],id[x],k);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);
	update(1,1,n,id[x],id[y],k);
}

inline int qSon(int x){
	res=0;
	query(1,1,n,id[x],id[x]+siz[x]-1);//子树区间右端点为id[x]+siz[x]-1 
	return res;
}

inline void updSon(int x,int k){//同上 
	update(1,1,n,id[x],id[x]+siz[x]-1,k);
}

树链求lca

inline int lca(int x,int y)
{
	while(top[x]!=top[y])//从深的点向上跳,直到x和y在一条链上
	{
		if(dep[top[x]]<dep[top[y]])
			swap(x,y);
		x=fa[top[x]];
	}
	if(dep[x]>dep[y])swap(x,y);公共祖先即为链上深度浅的结点
	return x;
}

字符串

马拉车算法


char a[12000000];
int R[23000000];
int manacher()
{
	string s="$#";
	int l1=strlen(a);
	for(int i=0;i<l1;i++)
	{
		s+=a[i];
		s+='#';
	}
	int len=2*l1+1;
	int mx=0,id=0;
	int max_len=0;

	for(int i=1;i<len;i++)
	{
		
		if(i<mx)
		{
			R[i]=min(R[2*id-i],mx-i);
		}
		else
		R[i]=1;
		while(s[i-R[i]]==s[i+R[i]])
		{
			R[i]++;
		}
		if(mx<i+R[i])
		{
			id=i;
			mx=i+R[i];
		}
		max_len=max(max_len,R[i]-1);
	}
	return max_len;
}
main(void)
{
	scanf("%s",&a);
	cout<<manacher();
}

kmp算法

比较字符串

  int j;
    j=0;//j可以看做表示当前已经匹配完的模式串的最后一位的位置 
    //如果看不懂,你也可以理解为j表示模式串匹配到第几位了 
    for(int i=1;i<=la;i++)
	   {
          while(j&&b[j+1]!=a[i])j=kmp[j];
		  //如果失配 ,那么就不断向回跳,直到可以继续匹配 
          if (b[j+1]==a[i]) j++;
          //如果匹配成功,那么对应的模式串位置++ 
          if (j==lb) 
		  {
		  cout<<i-lb+1<<endl;
		  j=kmp[j];
		  //继续匹配 
		  }
       }

求kmp

  j=0;
    for (int i=2;i<=lb;i++)
	   {     
	   while(j&&b[i]!=b[j+1])
       //此处判断j是否为0的原因在于,如果回跳到第一个字符就不 用再回跳了
       j=kmp[j];    
        //通过自己匹配自己来得出每一个点的kmp值 
       if(b[j+1]==b[i])j++;    
       kmp[i]=j;
        //i+1失配后应该如何跳 
       }

思路:利用kmp数组的含义来解。
kmp数组中储存的是这个字符串前缀和后缀中相同字符串的最长长度
1.一个串的最小循环节长度:len - kmp[len]。
2.若len%(len-kmp[len]) == 0, 则这个字符串的最小周期为len-kmp[len]。一定要注意前提是 len % (len - next[len]) == 0,否则不存在循环周期。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值