CQOI2016题目&CQOI2016题解&不同的最小割&K远点对&手机号码&密匙破解&路由表&伪光滑数

博主分享了参加CQOI2016竞赛的经历,从赛前准备到考试过程。重点讨论了比赛中涉及的算法问题,包括最小割问题的变种和求解平面内k远点对的方法,同时提及了数位动规和数学题的解题思路。尽管面临挑战,博主成功完成了比赛,并对未来充满期待。
摘要由CSDN通过智能技术生成

良好的心态是成功的一半。

                                           ------xinyue

Day 0

    到这个时候,做题确实也是不顶什么用的了,CQ今年省选给的考纲特别窄,特别妖,什么FFT,莫比乌斯,LCT都没给(还好没给)。和noip考前一样,我们机房8人上南山试机。键盘鼠标都还行,左边八中的,右边一中的,都不熟……,想着自己练Spaly练得少,就敲了个模板机械臂,当时没敲对,里面气氛又很闷,心头很慌,不敢再敲了。考前最重要的是心态,这个小失败确实是让人很沮丧的......早早就睡了,期望忘掉这些烦恼。因为模拟考试不理想的原因,我想了很久滚粗这个事了


Day1

    和上次进考场一样,8个人带教练一起在门口喊出“AK”的口号(有梦想就有奇迹),被隔壁学校以6666的回复嘲讽.........,进考场,分配到了一个大面包,一个小面包,一盒牛奶(没看到什么人吃)。T1很明显是抄的ZJOI2011的最小割,变了一下询问,裸的模板,练过几遍,被(850,8500)的数据范围吓到了点,写的时候特别注意了省去没必要的边和用数组预处理+前向星跑。

T2求平面上k远点对,一开始很懵逼,我连次远点对都不会求,果断先跳过。T3是很裸的数位动规。最后我回来把T2写了,因为用了double调了40min+的精度,还好最后弄完了。题解一起放下面。

T1 模板就不说了


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int N=865,M=100005;
const int INF=0x7fffffff/2;
struct node{int to,next,flow,anc;}q[M];
int h[N],cnt=1,dis[N],gap[N],prt[N];
int f[N][N],map[N][N],tmp[810000],top=0,n,m,S,T;
bool vst[N];
void qxx(int x,int y,int flow)
{
	cnt++;q[cnt].to=y;q[cnt].next=h[x];q[cnt].anc=flow;h[x]=cnt;
	cnt++;q[cnt].to=x;q[cnt].next=h[y];q[cnt].anc=flow;h[y]=cnt;
}
void Init()
{
	scanf("%d%d",&n,&m);
	int i,j,x,y,k;
	memset(f,0,sizeof(f));
	for(i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x,&y,&k);
		f[x][y]+=k;f[y][x]+=k;
	}
	for(i=1;i<=n;i++)
	 for(j=i+1;j<=n;j++)
	  if(f[i][j])qxx(i,j,f[i][j]);
}
int SAP(int x,int maxf)
{
	if(x==T)return maxf;
	int i,y,ret=0,dlt;
	for(i=h[x];i;i=q[i].next)
	{
		y=q[i].to;
		if(dis[x]==dis[y]+1&&q[i].flow>0)
		{
			dlt=SAP(y,min(maxf,q[i].flow));
			q[i].flow-=dlt;
			q[i^1].flow+=dlt;
			maxf-=dlt;
			ret+=dlt;
			if(!maxf||dis[S]>=n)return ret;
		}
	}
	if(!(--gap[dis[x]]))dis[S]=n;
	gap[++dis[x]]++;
	return ret;
}
void DFS(int x)
{
	vst[x]=1;
	int i,y;
	for(i=h[x];i;i=q[i].next)
	{
		y=q[i].to;
		if(!vst[y]&&q[i].flow>0)DFS(y);
	}
}
void Gusfiled()
{
	int i,j,ans;
	for(i=1;i<=n;i++)
	 for(j=1;j<=n;j++)map[i][j]=INF;
	for(i=2;i<=n;i++)prt[i]=1;
	for(i=2;i<=n;i++)
	{
		for(j=2;j<=cnt;j++)q[j].flow=q[j].anc;
		for(j=0;j<=N-3;j++)dis[j]=gap[j]=vst[j]=0;
		S=prt[i];T=i;
		ans=0;
		while(dis[S]<=n)ans+=SAP(S,INF);
		DFS(S);
		for(j=i+1;j<=n;j++)
		 if(prt[j]==prt[i]&&!vst[j])prt[j]=i;
		for(j=1;j<=i-1;j++)
		 map[i][j]=map[j][i]=min(ans,map[prt[i]][j]);
	}
	for(i=1;i<=n;i++)
	 for(j=i+1;j<=n;j++)tmp[++top]=map[i][j];
	sort(tmp+1,tmp+top+1);
	tmp[0]=-1;
	int Add=0;
	for(i=1;i<=top;i++)
	 if(tmp[i]!=tmp[i-1])Add++;
	printf("%d",Add);
}
int main()
{
	Init();
	Gusfiled();
	return 0;
}


T2 大意:求平面上k远点对

    很有意思的一道题,凸包+旋转卡壳。

    只会写平面上最远点对,现在要求平面上k远点对,那么总思路就是把k远点对转成最远点对。

   当求到现在的最远点对(point1,point2)后,若不加处理,下次若继续求最远点对,一定还是(point1,point2),这不是我们想要的,故,要删除这个点对。删后再求最远点对,那么就是次远点对了,以此处理,最终会求得k远点对。那么问题就是删除操作,一个点对由两个点组成,任意删除一个点,这个点对将不存在,我们现在要考虑删除哪个点,我使用的极角排序,正常时候,每次凸包+卡壳的时间其实是O(nlogn+n),logn 是极角排序所带来的,从范围来看,这道题O(kn)是最合理的,显然,每次求最远点对,我不能极角排序,所以,我们要固定编号为1的点(我的代码里是y坐标最小的点中x坐标最小的)。那么删除的时候,就删除标号大的一个点,即为point2。删点的时候,考虑将会带来哪些影响,显然,图中现在存在的点和point2的距离将因为删点永远不会被后面计算到,那么我们就暴力枚举图中剩下的点,求出他们与point2的距离,保存下来,这样,就可以放心地删掉这个点了。最后的部分就是对于那些保存下来的点对距离的处理。每一次删点,理论上最多会有n个点对距离需要保存,设一个Ans[]数组,Ans[i]保存的是前面的计算过程中,第i远点对距离,所以在要保留点对的时候,如果这个距离dis小于当前的Ans[k]就没有必要保存了,每次弄完,把Ans[]排一遍,保存最大的k个,如果某一次没有任何点对距离大于Ans[k],那么break,因为当前平面上最远点已经无法更新Ans[]了,Ans[k]即为所求。代码如下。


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const double Eps=1e-10;
const LL N=200005LL,INF=100000000000000000LL;
struct point{LL x,y,i;double ag;}a[N],p[N];
LL n,m,Ans[N];
bool vst[N];
LL Dis(point p1,point p2)
{
	LL x=p1.x-p2.x,y=p1.y-p2.y;
	return x*x+y*y;
}
LL Cross(point p1,point p2,point p3)
{
	return (p1.x-p3.x)*(p2.y-p3.y)-(p2.x-p3.x)*(p1.y-p3.y);
}
bool cmp(const point p1,const point p2)
{
	if(fabs(p1.ag-p2.ag)<Eps)return Dis(a[1],p1)<Dis(a[1],p2);
	return p1.ag<p2.ag;
}
void Init()
{
	scanf("%lld%lld",&n,&m);
	LL i,j,k;
	for(i=1;i<=n;i++)scanf("%lld%lld",&a[i].x,&a[i].y);
	LL Minx=INF,Miny=INF;
	for(i=1;i<=n;i++)
	 if(a[i].y<Miny||(a[i].y==Miny&&a[i].x<Minx))
	 {
	 	Miny=a[i].y;Minx=a[i].x;k=i;
	 }
	swap(a[1],a[k]);
	for(i=2;i<=n;i++)a[i].ag=atan2(a[i].y-a[1].y,a[i].x-a[1].x);
	sort(a+2,a+n+1,cmp);
	for(i=1;i<=n;i++)a[i].i=i;
}
bool cmp2(const LL x,const LL y){return x>y;}
void Solve()
{
	LL ti,i,j,k,x,y,top,num=0,dis;
	Ans[0]=-1;
	for(ti=1;ti<=m;ti++)
	{
		top=0;
		for(i=1;i<=n;i++)
		{
			if(vst[a[i].i])continue;
			while(top>=2&&Cross(p[top],a[i],p[top-1])<=0)top--;
			p[++top]=a[i];
		}
		dis=0;
		p[0]=p[top];p[top+1]=p[1];
		j=1;
		for(i=1;i<=top;i++)
		{
			while(Dis(p[i],p[j])<=Dis(p[i],p[(j+1)%top]))j=(j+1)%top;
			if(Dis(p[i],p[j])>dis)
			{
				dis=Dis(p[i],p[j]);
				x=p[i].i;y=p[j].i;
			}
		}
		if(x>y)swap(x,y);
		vst[y]=1;
		k=0;
		for(i=1;i<=n;i++)
		{
			if(vst[i])continue;
			if(Dis(a[y],a[i])>Ans[num])
			{
				k++;
				Ans[num+k]=Dis(a[y],a[i]);
			}
		}
		if(!k)break;
		sort(Ans+1,Ans+num+k+1,cmp2);
		num=min(m,num+k);
	}
	printf("%lld",Ans[m]);
}
int main()
{
	Init();
	Solve();
	return 0;
}

T3 大意:求区间[L,R]内不同时出现4,8且有三个连续相同的数的个数

    用记搜版的DP方便一些,dp[pos][Las2][Las1][bj4][bj8][flag][jud][sta]表示当前枚举到第pos位,pos+1位是Las1,pos+2位是Las2

(若无则为-1),bj4,bj8为前面是否有4,8两个数,flag为前面的数是否抵满了上界,jud为前面是否已经满足有三个连续相同的数,sta表示前面是否有数(判前导0用的)。代码如下。


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
LL f[15],len=0;
LL dp[15][12][12][2][2][2][2];
LL SPE(LL x,LL y,LL z)
{
	if(x==-1||y==-1||z==-1)return 0;
	if(x==y&&y==z)return 1;
	return 0;
}
LL DFS(LL pos,LL Las2,LL Las1,LL bj4,LL bj8,LL flag,LL jud,LL sta)
{
	if(!pos)
	{
		if(bj4&&bj8)return 0;
		return jud;
	}
	if(!flag&&Las2!=-1&&Las1!=-1)
	 if(dp[pos][Las2][Las1][bj4][bj8][jud][sta]!=-1)
	  return dp[pos][Las2][Las1][bj4][bj8][jud][sta];
	LL i,j,spe,ed=9,add=0;
	if(flag)ed=f[pos];
	for(i=0;i<=ed;i++)
	{
		if(!sta&&!i)j=-1;else j=i;
		spe=SPE(Las2,Las1,j);
		add+=DFS(pos-1,Las1,j,bj4||(i==4),bj8||(i==8),flag&&(i==ed),jud||spe,sta||i);
	}
	if(!flag&&Las2!=-1&&Las1!=-1)
	 dp[pos][Las2][Las1][bj4][bj8][jud][sta]=add;
	return add;
}
LL solve(LL n)
{
	len=0;
	while(n){f[++len]=n%10;n/=10;}
	return DFS(len,-1,-1,0,0,1,0,0);
}
int main()
{
	memset(dp,-1,sizeof(dp));
	LL n,m,ans=0;
	scanf("%lld%lld",&n,&m);
	ans-=solve(n-1);ans+=solve(m);
	printf("%lld",ans);
	return 0;
}

很幸运,Day1成功AK!



Day2 

    上山,等待,相互加油,这些操作都是差不多的。进去过后,T1是道数学题(模板题),一个Pollard Rho的分解,和你想装逼就可以加上的Miller_Rabin+Witnesse二次探测。第二题我坚信是考语文,这描述一绕一绕的,估计看的时候都懵逼了一阵子,读懂了挺简单的,就是一个01的可持久trie。T3一看就有点小麻烦(从没想过暴搜),在中途写错了3次的情况下,最后10min把程序调了出来,因为是800000的数据,我开不下,开的650000,我以为过不了的,就贴了份暴力,啊啊啊啊啊啊啊啊!30分啊,AK伏笔啊,不手抽贴那个暴力多好啊。。。。。。。。(&*^&*#!@*#^*!@#) 题解代码见下。

T1大意:解码

    很少见的按要求写代码。。。。。说什么做什么就好了,其实很多条件不用给,可以用离散对数自己推出r=(p1-1)*(p2-1)和ed=1(mod r)  r 即φ(N),这里就不说了。代码如下。


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
LL C,E,N,num=0,g[15];
LL gcd(LL x,LL y)
{
	if(!y)return x;
	return gcd(y,x%y);
}
LL Exgcd(LL a,LL b,LL &x,LL &y)
{
	if(!b){x=1;y=0;return a;}
	else
	{
		LL tmp=Exgcd(b,a%b,x,y);
		LL t=x;x=y;y=t-a/b*y;
		return tmp;
	}
}
LL exgcd(LL a,LL b,LL c)
{
	LL d,x,y;
	d=Exgcd(a,b,x,y);
	if(c%d)return -1;
	x=(x*(c/d)%(b/d)+(b/d))%(b/d);
	return x;
}
LL Mul(LL a,LL b,LL p)
{
	LL ans=0;
	while(b)
	{
		if(b&1)ans=(ans+a)%p;
		a=(a+a)%p;
		b>>=1;
	}
	return ans;
}
LL Ksm(LL a,LL b,LL p)
{
	LL ans=1;
	while(b)
	{
		if(b&1)ans=Mul(ans,a,p);
		a=Mul(a,a,p);
		b>>=1;
	}
	return ans;
}
LL Pollard(LL n,LL c)
{
	LL i=1,k=2,x,y,d;
	x=rand()%(n-1)+1;
	y=x;
	while(1)
	{
		i++;
		x=(Mul(x,x,n)+c)%n;
		d=gcd(y-x,n);
		if(1<d&&d<n)return d;
		if(x==y)return n;
		if(i==k){y=x;k<<=1;}
	}
}
void Find(LL n,LL k)
{
	if(n==1)return;
	if(n!=N){g[++num]=n;return;}
	LL p=n;
	while(p>=n)p=Pollard(p,k--);
	Find(p,k);
	Find(n/p,k);
}
void Solve()
{
	LL R,M,D;
	num=0;
	Find(N,10007);
	R=(g[1]-1)*(g[2]-1);
	D=exgcd(E,R,1);
	M=Ksm(C,D,N);
	printf("%lld %lld",D,M);
}
int main()
{
	srand(19990510);
	scanf("%lld%lld%lld",&E,&N,&C);
	Solve();
	return 0;
}
/*
3 187 45
*/

T2 大意:很复杂的匹配..........

    从区间[L,R]的限制上不难想到可持久化,添加一个字符串的时候,只有在这个串的结束位置,将它的size令为前缀与其匹配的,最长的串的size+1,这样一个点的size即为第一串到当前串,匹配表项的改变次数。当询问的时候,其实掩码就相当于32,利用可持久化,做区间中减法,同理,都是找最长的串的size作为全值,即为所求。代码如下。




#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=34000005,M=2000005;
int tr[N][2],sum[N],root[M],sign=0;
int Numb[10],jilu[40],tmp[40],len;
char s[40];
void Get()
{
	int i,j,k=0;
	memset(jilu,0,sizeof(jilu));
	memset(tmp,0,sizeof(tmp));
	for(i=4;i>=1;i--)
	{
		j=0;
	    while(Numb[i])
		{
			j++;
		    jilu[k+j]=Numb[i]%2;
		    Numb[i]/=2;
		}
		k+=8;
	}
	for(i=k;i>=k-len+1;i--)tmp[k-i+1]=jilu[i];
}
int Insert(int rt,int pos,int val)
{
	int i,x;
	x=++sign;
	for(i=0;i<=1;i++)tr[x][i]=tr[rt][i];sum[x]=sum[rt];
	if(pos>len){sum[x]=val+1;return x;}
	int k=tmp[pos];
	if(sum[tr[rt][k]])val=sum[tr[rt][k]];
	tr[x][k]=Insert(tr[rt][k],pos+1,val);
	return x;
}
int Query(int rt1,int rt2,int pos,int val1,int val2)
{
	if(pos>len)return val1-val2;
	int k=tmp[pos];
	if(sum[tr[rt1][k]])val1=sum[tr[rt1][k]];
	if(sum[tr[rt2][k]])val2=sum[tr[rt2][k]];
	return Query(tr[rt1][k],tr[rt2][k],pos+1,val1,val2);
}
int main()
{
	int n=0,i,j,Q,x,y;
	scanf("%d",&Q);
	for(i=1;i<=Q;i++)
	{
		scanf("%s",s);
		if(s[0]=='A')
		{
			scanf("%d.%d.%d.%d/%d",&Numb[1],&Numb[2],&Numb[3],&Numb[4],&len);
			Get();
			n++;root[n]=Insert(root[n-1],1,0);
		}
		else
		{
			scanf("%d.%d.%d.%d",&Numb[1],&Numb[2],&Numb[3],&Numb[4]);
			scanf("%d%d",&x,&y);
			len=32;Get();
			printf("%d\n",Query(root[y],root[x-1],1,0,0));
		}
	}
	return 0;
}
T3 大意:(不好描述,看题目吧)

    时间复杂度,一定是要依托于k来计算,看似要枚举的东西很乱,细细的规划一下,可以想到把他们以一个二元组区分(p,size)

表示一个数的最大素数为p,且为size个素数相乘,一开始预处理,就可以求出2-127这31个质数的最大size,即 pi^size[i]>=N(size[i]取到最小)(这样能保证之后的所有状态的权值都是小于N的),一开始,我们的状态数就只有sigma(size[i])  ,1<=i<=31(表示第i个质数)  ,即一开始时,每一个二元组只有一个有效状态,(该二元组的其他所有状态一定没有当前状态值优),且这些状态表示的序列都为 size 个 p。该状态的权值即为pi^size[i]。因为要频繁询问当前最大权值和具有修改操作,我选择了可并堆。每一次,取出可并堆的堆顶元素,即为最大权值,表示我现在选择了它,可以找到它原来的那个序列,那么现在就要利用这个序列扩充新的序列。设size为这个二元组的size,p为这个二元组的p,那么相当于是要找到size个素数相乘,且最大素数为p。规定要用最小表示法,即这size个素数单调不下降组成一个序列,这样,我们就要枚举将其中的哪一个素数变小,它变化后不能破坏这个序列单调性,在枚举完后,会有一个新的权值(可以O(1)计算得),它可能已经在前面搜索中进堆了(举例来说,对于一个二元组(7,5),最初始为7*7*7*7*7,它接下来会搜索到序列(不是直接枚举到) 5*5*7*7*7 (记为f1)和3*7*7*7*7(记为f2) 显然f1会f2先出堆,f1 会搜到序列 3*5*7*7*7(记为f3),那么f3已经入堆了,之后如果f2出堆了,那么它也会枚举到f3,但此时f3已经不能入堆,否则将有一些数被算重),因此这里加一个哈希表来判。以此处理,每次出堆会算出当前最大值,且最多会多进入60个新的序列(其实远远达不到),那么时间复杂度就是多项式,O(k*logm)m为可并堆里面的元素个数。数组可能会吃紧,考虑到一个序列出堆后就没用了,可以写个回收站来回收空间以图再利用(可并堆里的元素也是如此)。这样虽然代码长了点,也能很好的解决这个问题了(ORZ%%%%%搜索+减枝过的),可能叙述有些难懂,代码还是很好理解的。(代码里用i表示第i个素数pi)


#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL N=650005,mod=1000003;
LL prime[200],num=0,size[200],m,NNN;
LL jilu[N],Add=0,He=0,SPE=0;
LL tmp[N]={0},top=0;
struct data{LL size,i;}P[2500];LL cnt=0;
LL map[N][62]; 
struct node{LL L,R,val,i;}tr[N];LL sign=0,root;
bool vst[200];
struct Haxi
{
	LL h[1000005],tot;
	struct qxx{LL to,next;}q[8000005];
	LL Ask(LL val)
	{
		LL i,x=val%mod;
		for(i=h[x];i;i=q[i].next)
			if(q[i].to==val)return 1;
		return -1;
	}
	LL Insert(LL val)
	{
		LL i,x=val%mod;
		tot++;
		q[tot].to=val;q[tot].next=h[x];h[x]=tot;
	}
}pq;
LL CNTNUM()
{
	if(Add)return jilu[Add--];
	return ++He;
}
LL CNTclean(LL x){jilu[++Add]=x;}
LL Numb()
{
	if(top)return tmp[top--];
	return ++sign;
}
void Clean(LL x)
{
	tr[x].L=tr[x].R=tr[x].i=tr[x].val=0;
	tmp[++top]=x;
}
void Build()
{
	LL i,j,x;
	for(i=2;i<=128;i++)
	{
		if(!vst[i])prime[++num]=i;
		for(j=1;j<=num;j++)
		{
			if(i*prime[j]>128)break;
			vst[i*prime[j]]=1;
			if(i%prime[j]==0)break;
		}
    }
    LL n;
	scanf("%lld%lld",&n,&m);
	for(i=1;i<=num;i++)
	{
		x=n;j=0;
		while(x>=prime[i]){x/=prime[i];j++;}
		size[i]=j;
	}
}
LL Ksm(LL a,LL b)
{
	LL ans=1;
	while(b)
	{
		if(b&1)ans=ans*a;
		a=a*a;
		b>>=1;
	}
	return ans;
}
LL Merge(LL x,LL y)
{
	if(!x||!y)return x+y;
	if(tr[x].val<tr[y].val)swap(x,y);
	tr[x].R=Merge(tr[x].R,y);
	swap(tr[x].L,tr[x].R);
	return x;
}
void Pop()
{
	LL x=root;
	root=Merge(tr[root].L,tr[root].R);
	Clean(x);
}
void Solve()
{
	LL i,j,x,k;
	pq.tot=0;
	for(i=1;i<=num;i++)
	  for(j=1;j<=size[i];j++)
	  {
		 cnt=CNTNUM();P[cnt].size=j;P[cnt].i=i;
	  }
	LL nowval;
	root=0;
	for(i=1;i<=He;i++)
	{
		nowval=Ksm(prime[P[i].i],P[i].size);
		for(j=1;j<=P[i].size;j++)map[i][j]=P[i].i;map[i][0]=P[i].size;
		x=Numb();
		tr[x].L=tr[x].R=0;tr[x].i=i;tr[x].val=nowval;
		pq.Insert(nowval);
		root=Merge(root,x);
	}
	LL Ti,bj,Toval;
	for(Ti=1;Ti<=m;Ti++)
	{
		i=tr[root].i;nowval=tr[root].val;
		if(Ti==m){printf("%lld",nowval);break;}
		Pop();
		for(j=1;j<=map[i][0]-1;j++)
		{
			if(map[i][j]>1&&(map[i][j]>map[i][j-1]||j==1))
			{
				Toval=nowval;
				Toval=Toval/prime[map[i][j]]*prime[map[i][j]-1];
				if(pq.Ask(Toval)==-1)pq.Insert(Toval);
				else continue;
				cnt=CNTNUM();
				for(k=0;k<=map[i][0];k++)map[cnt][k]=map[i][k];
				map[cnt][j]--;
				x=Numb();
				tr[x].L=tr[x].R=0;tr[x].i=cnt;tr[x].val=Toval;
				root=Merge(root,x);
			}
		}
		CNTclean(i);
	}
}
int main()
{
	Build();
	Solve();
	return 0;
}

最终Day2小遗憾270 没能AK 被lgz成功 爆菊


小结 300+270 省选的结束也算这一重庆阶段良好收官,再接再厉,希望能在接下来的考试中继续前行。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值