并不对劲的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\))
题解
该图为接在同一个环上的很多树。
每个树上的路径数为\(\frac{点数\times (点数-1)}{2}\)。
在环上选两个点\(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,siz[maxn];
LL 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);
siz[u]+=siz[v[k]];
}
siz[u]++;
}
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]=siz[i]=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),ans+=(LL)siz[r[i]]*(siz[r[i]]-1)/2ll;tmp=0;
rep(i,1,cntr)
{
ans+=(siz[r[i]])*tmp*2ll;
tmp+=siz[r[i]];
}
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;
}