其他分享
首页 > 其他分享> > 并不对劲的CF1454D&E&F: Number into Simple Partition

并不对劲的CF1454D&E&F: Number into Simple Partition

作者:互联网

CF1454D: Number into Sequence

题目大意

给出一个正整数\(n\)(\(n>1\))。
你需要找出一个正整数序列\(a_1,a_2,...,a_k\)满足:
1.\(\forall i\in\{ 1,2,...,k\},a_i>1\);
2.\(a_1\times a_2\times ...\times a_k=n\);
3.\(\forall i\in \{1,2,..,k-1\},a_{i+1}\)能被\(a_i\)整除;
4.\(k\)尽可能大。
如果有多个答案,你可以输出任意一个。共\(t\)组询问。(\(1 \le t \le 5000;2\leq n\leq 10^{10}\),所有\(n\)之和不超过\(10^{10}\))

题解

将\(n\)分解质因数,得到\(n=c_1^{b_1}\times c_2^{b_2}\times ...\times c_m^{b_m}\)。
\(k\)最大不会超过质因数的指数中的最大值。
为了使\(k\)达到这个最大值,有一种构造方法是:
假设\(b_x=max(b_1,b_2,...,b_m)\),则\(a_1,a_2,...,a_{k-1}=c_x\),\(a_k=\frac{n}{c_x^{b_x-1}}\)

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define LL long long
#define maxn 100007
using namespace std;
LL read()
{
	LL x=0;int f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1ll)+(x<<3ll)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10ll+'0',x/=10ll;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
void write_(LL x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10ll+'0',x/=10ll;
	while(f)putchar(ch[f--]);
	putchar(' ');
	return;
}
LL n,p[maxn];
int t,no[maxn],cnt,lim=100000,a[maxn],b[maxn];
int main()
{
	no[1]=1;
	rep(i,2,lim)
	{
		if(!no[i])p[++cnt]=i;
		for(int j=1;j<=cnt&&(LL)i*p[j]<=(LL)lim;j++)
			no[i*p[j]]=1;
	}
	t=read();
	while(t--)
	{
		n=read();
		int nump=0,mx=(int)floor(sqrt((double)n)),mxp=0;
		rep(i,1,cnt)
		{
			if(p[i]>mx)break;
			if(n%((LL)p[i])==0)a[++nump]=p[i];
		}
		if(nump==0){write(1),write(n);continue;}
		rep(i,1,nump)
		{
			LL tmp=n;b[i]=0;
			while(tmp%((LL)a[i])==0)tmp/=a[i],b[i]++;
			if(mxp==0)mxp=i;
			else if(b[i]>b[mxp])mxp=i;
		}
		write(b[mxp]);LL tmpans=1;
		rep(i,1,b[mxp]-1)
		{
			tmpans*=(LL)a[mxp];
			write_(a[mxp]);
		}
		write_(n/tmpans);
		puts("");
	}
	return 0;
}

CF1454E: Number of Simple Paths

题目大意

给出一个\(n\)个点\(n\)条边的无重边无自环的连通无向图。
请求出该图中有多少条至少包括一条边的无向简单路径。有\(t\)组询问。
(\(1 \le t \le 2\times 10^4;3\le n\le 2\times 10^5\),且所有测试数据中\(n\)之和不超过\(2\times 10^5\))

题解

该图为接在同一个环上的很多树。
在每个树上计算出无向简单路径树。
在环上选两个点\(x,y\),经过这两个点的路径数等于\(以x为根的树的大小\times以y为根的树的大小\times 2\)。

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200007
#define maxm 400007
#define LL long long
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
	return;
}
int vis[maxn],fir[maxn],nxt[maxm],v[maxm],cnte,ring,r[maxn],cntr,yesr[maxn];
int t,n;
LL f[maxn][5],ans,tmp;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void adr(int u1){r[++cntr]=u1,yesr[u1]=1;}
void getr(int u,int fa)
{
	vis[u]=1;
	view(u,k)if(v[k]!=fa)
	{
		if(vis[v[k]])ring=v[k];
		else getr(v[k],u);
		if(ring!=0)break;
	}
	if(ring!=0&&ring!=-1)adr(u);
	if(ring==u)ring=-1;
}
void getf(int u,int fa)
{
	view(u,k)if(v[k]!=fa&&!yesr[v[k]])
	{
		getf(v[k],u);
		f[u][1]+=(f[u][0]+1)*(f[v[k]][0]+1ll);
		f[u][0]+=f[v[k]][0]+1ll;
	}
	ans+=f[u][1];
}
int main()
{
	t=read();
	while(t--)
	{
		n=read();ring=cnte=cntr=0;ans=0;
		rep(i,1,n)fir[i]=-1,vis[i]=yesr[i]=f[i][0]=f[i][1]=0;
		rep(i,1,n){int x=read(),y=read();ade(x,y),ade(y,x);}
		getr(1,0);
		rep(i,1,cntr)getf(r[i],0);tmp=0;
		rep(i,1,cntr)
		{
			ans+=(f[r[i]][0]+1)*tmp*2ll;
			tmp+=f[r[i]][0]+1;
		}
		write(ans);
	}
	return 0;
}

CF1454F: Array Partition

题目大意

给出一个\(n\)个正整数的数组\(a\)。
设\(min(l,r)\)(\(1\le l\le r\le n\))表示\(a_l,a_{l+1},...,a_r\)的最小值,\(max(l,r)\)(\(1\le l\le r\le n\))表示\(a_l,a_{l+1},...,a_r\)的最大值。
请找出三个正整数\(x,y,z\),满足:
1.\(x+y+z=n\);
2.\(max(1,x)=min(x+1,x+y)=max(x+y+1,n)\)。
如果有多组解,输出任意一组。
如果不存在符合条件的解,输出\(NO\)。
有\(t\)组询问。(\(1 \le t \le 2\times 10^4;3\le n\le 2\times 10^5\),且所有测试数据中\(n\)之和不超过\(2\times 10^5;1\le a_i\le 10^9\))

题解

\(x\)确定时,\(min(x+1,x+y)\)和\(max(x+y+1,n)\)有单调性。故可枚举\(x\),二分\(y\)。

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 200007
#define maxb 21
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(int x)
{
	if(x==0){putchar('0'),putchar('\n');return;}
	int f=0;char ch[20];
	if(x<0)putchar('-'),x=-x;
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar(' ');
	return;
}
int mna[maxn][maxb],a[maxn],n,t;
int bac[maxn],lim,mxa[maxn];
int getmn(int l,int r)
{
	int x=bac[r-l+1];
	return min(mna[l][x],mna[r-(1<<x)+1][x]);
}
int main()
{
	t=read();lim=18;
	lim=200000;int tmp=0;
	rep(i,1,lim)
	{
		if((1<<(tmp+1))<=i)tmp++;
		bac[i]=tmp;
	}
	while(t--)
	{
		n=read();
		rep(i,1,n)a[i]=read(),mna[i][0]=a[i];
		lim=0;while((1<<(lim+1))<=n)lim++;
		dwn(i,n,1)
			for(int k=1;i+(1<<k)-1<=n;k++)
				mna[i][k]=min(mna[i][k-1],mna[i+(1<<(k-1))][k-1]);
		mxa[n]=a[n];
		dwn(i,n-1,1)mxa[i]=max(mxa[i+1],a[i]);
		int ansx=-1,ansy=-1,mx=0;
		rep(x,1,n-1)
		{
			mx=max(a[x],mx);
			int l=x+1,r=n-1,ans=-1;
			while(l<=r)
			{
				int mi=((l+r)>>1);
				if(mx==mxa[mi+1])
				{
					int mn=getmn(x+1,mi);
					if(mn==mx){ans=mi;break;}
					else if(mn<mx){r=mi-1;}
					else l=mi+1;
				}
				else if(mxa[mi+1]<mx)r=mi-1;
				else l=mi+1;
			}
			if(ans!=-1){ansy=ans-x,ansx=x;break;}
		}
		if(ansx==-1)puts("NO");
		else
		{
			puts("YES");
			write(ansx),write(ansy),write(n-ansx-ansy);puts("");
		}
		dwn(i,n,1)
			for(int k=1;i+(1<<k)-1<=n;k++)
				mna[i][k]=0;
	}
	
	return 0;
}

标签:CF1454D,le,Simple,Partition,times,int,ch,include,define
来源: https://www.cnblogs.com/xzyf/p/16517163.html