被教练坑了。
并没有任何卵用的成电宣传活动。
题目全是成电acm训练的原题,而且画风诡秘,4h4题。
还因为建了子文件夹爆了0。
最大疯子树
【题目描述】
给定一棵 n 个结点的树,结点编号为 1~n,i 号结点的权重记为 wi(每个点
的权值各不相同)。我们定义一个“疯子树”为:
1. 是一个联通子图。
2. 我们将子图内的点按照权重从小到大排序后序列为 b1,b2,…,bm,对于任
意的 i(i<m),bi到 bi+1最短路径(不含 bi和 bi+1)上的结点的权值都小于
等于 i wb 。
输出包含结点最多的“疯子树”的结点数。
【输入格式】
数据有多组 case,文件以 EOF 结束,每组第一行输入一个 n 表示树的节点数;
接下来一行包含 n 个整数,第 i 个数表示 i 号结点的权重 wi;接下行 n-1 行,第
i 行包含 2 个整数 ui, vi,表示 ui和 vi有一条边。
【输出格式】
对于每组 case 输出一行,包含一个整数,表示包含结点最多的“疯子树”
的结点数。
【样例输入】
5
1 4 2 3 5
1 2
2 3
3 4
4 5
5
2 5 4 1 3
1 2
2 3
3 4
4 5
【样例输出】
4
4
【数据范围】
对于 10%的数据有所有组的 n 之和 n≤20。
对于 30%的数据有所有组的 n 之和 n≤2000。
3
对于 100%的数据有所有组的 n 之和 n≤200000,0 < wi≤100000000,n 为正
整数。
dp水题。发现要求选出来的子树就是一颗从跟向叶子走去权值一路变大的树。
f表示从我往儿子和父亲权值比我大的走的最大总大小,g表示从我往儿子或父亲权值比我小的走能走最长的路径。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
const int N=200007;
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
typedef double db;
using namespace std;
int n,w[N],f[N],g[N],ans;
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int ecnt,fir[N],nxt[N<<1],to[N<<1];
void add(int u,int v) {
nxt[++ecnt]=fir[u]; fir[u]=ecnt; to[ecnt]=v;
nxt[++ecnt]=fir[v]; fir[v]=ecnt; to[ecnt]=u;
}
void dfs(int x,int fa) {
f[x]=1;
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa) {
dfs(to[i],x);
if(w[to[i]]<w[x]) g[x]=max(g[x],g[to[i]]+1);
else f[x]+=f[to[i]];
}
}
void calc(int x,int fa) {
if(fa) {
if(w[fa]>w[x]) f[x]=f[x]+f[fa];
else g[x]=max(g[x],g[fa]+1);
}
ans=max(ans,f[x]+g[x]);
for(int i=fir[x];i;i=nxt[i]) if(to[i]!=fa)
calc(to[i],x);
}
#define DEBUG
int main() {
#ifdef DEBUG
freopen("crazy.in","r",stdin);
freopen("crazy.out","w",stdout);
#endif
while(scanf("%d",&n)!=EOF) {
For(i,1,n) read(w[i]);
ecnt=0;
For(i,1,n-1) {
int u,v;
read(u); read(v);
add(u,v);
}
ans=0;
dfs(1,0);
calc(1,0);
printf("%d
",ans);
For(i,1,n) fir[i]=0,g[i]=0;
}
return 0;
}
/*
5
1 4 2 3 5
1 2
2 3
3 4
4 5
5
2 5 4 1 3
1 2
2 3
3 4
4 5
*/
分解
【题目描述】
给定正整数 N,你需要将其分解为若干正整数的乘积,要求分解出的数之间 相差都不超过 1。
【输入格式】
第一行一个正整数 T,表示数据组数。 接下来 T 行,每行一个正整数 N,意义如题面所示。
【输出格式】
对于每组数据,首先输出一行,一个整数 P,表示有几组可行解,如果有无穷 多组解,输出-1。
若没有无穷多组解,接下来输出 P 行,每行首先输出一个正整数 M,表示将 N 分解为几个数,接下来输出 M 个数,表示分解出的数。
如有多组解,请将分解出的数字从小到大排序,记为序列 c1c2...cM,按照该 序列的字典序,将解从小到大输出
。 一组解分解出多个数时,请先输出较小的数。
【样例输入】
2
1
12
【样例输出】
-1
3
3 2 2 3
2 3 4
1 12
【数据范围】
对于 20%的数据 N≤100
对于 40%的数据 N≤109
对于 100%的数据 N≤1018,T≤10
一道pallord_rho模板练习题。
先质因数分解了,最多17个质因数,因为x和x+1互质,暴力枚举哪些质因子归x即可。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
typedef double db;
using namespace std;
int T,cnt[107];
LL n,p[107],P=1e18;
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
LL ksc(LL a,LL b,LL mod) {
LL bs=a%mod,rs=0;
while(b) {
if(b&1) rs=(rs+bs)%mod;
bs=(bs+bs)%mod;
b>>=1;
}
return rs;
}
LL ksm(LL a,LL b,LL mod) {
LL bs=a%mod,rs=1;
while(b) {
if(b&1) rs=ksc(rs,bs,mod);
bs=ksc(bs,bs,mod);
b>>=1;
}
return rs;
}
LL easy_ksm(LL a,LL b) {
LL bs=a,rs=1;
while(b) {
if(b&1) rs=rs*bs;
bs=bs*bs;
b>>=1;
} return rs;
}
int miller_rabin(LL n) {
if(n==2||n==3||n==5||n==7||n==11) return 1;
if(!(n%2)||!(n%3)||!(n%5)||!(n%7)||!(n%11)) return 0;
LL u=n-1,k=0;
while(!(u&1)) { u>>=1; k++; }
For(ti,1,17) {
LL a=rand()%(n-2)+2;
LL x=ksm(a,u,n),y=x;
For(i,1,k) {
x=ksc(x,x,n);
if(x==1&&y!=1&&y!=n-1) return 0;
y=x;
}
if(x!=1) return 0;
}
return 1;
}
LL gcd(LL a,LL b) { return !b?a:gcd(b,a%b); }
LL pallord_rho(LL n,LL c) {
LL x=rand()%(n-1)+1,y=x;
for(int i=2,k=2;;i++) {
x=(ksc(x,x,n)+c)%n;
LL tp=gcd((x-y+n)%n,n);
if(tp>1&&tp<n) return tp;
if(x==y) return n;
if(i==k) y=x,k+=k;
}
}
void find(LL n) {
if(n==1||miller_rabin(n)) {
p[++p[0]]=n; return;
}
LL tp=n;
for(LL c=13;;c++) {
tp=pallord_rho(n,c);
if(tp>1&&tp<n) break;
}
find(tp); find(n/tp);
}
int ok(LL a,LL b) {
if(b%a) return 0;
int rs=0;
while(b!=1) {
if(b%a) return 0;
rs++; b/=a;
} return rs;
}
struct Ans{
LL a,b,ca,cb;
Ans(){}
Ans(LL a,LL b,LL ca,LL cb):a(a),b(b),ca(ca),cb(cb){}
friend bool operator <(const Ans&A,const Ans&B) {
return A.a<B.a||(A.a==B.a&&A.ca<B.ca||(A.a==B.a&&A.ca==B.ca&&A.b<B.b));
}
}ans[100007];
#define DEBUG
int main() {
#ifdef DEBUG
freopen("little.in","r",stdin);
freopen("little.out","w",stdout);
#endif
srand(998244353);
read(T);
while(T--) {
read(n); p[0]=0;
find(n);
sort(p+1,p+p[0]+1);
int c1=0;
for(int i=1,j;i<=p[0];) {
LL pr=p[i];
j=i; c1++;
while(j<=p[0]&&p[j]==pr) j++;
cnt[c1]=j-i; i=j;
}
if(c1==1&&(p[1]==1||p[1]==2)) puts("-1");
else {
unique(p+1,p+p[0]+1);
int nn=(1<<c1)-1,totans=0;
For(i,1,nn) {
LL g=0;
For(j,1,c1)
if(i&(1<<j-1)) {
if(!g) g=cnt[j];
else g=gcd(g,cnt[j]);
}
For(j,1,g) if(!(g%j)) {
LL tp1=1,tp2=1,tt;
For(k,1,c1) {
if(i&(1<<k-1))
tp1*=easy_ksm(p[k],cnt[k]/j);
else tp2*=easy_ksm(p[k],cnt[k]);
}
if(tp2==1)
ans[++totans]=Ans(tp1,1,j,0);
else {
tt=ok(tp1+1,tp2);
if(tt)
ans[++totans]=Ans(tp1,tp1+1,j,tt);
}
}
}
sort(ans+1,ans+totans+1);
printf("%d
",totans);
For(j,1,totans) {
printf("%d ",ans[j].ca+ans[j].cb);
For(k,1,ans[j].ca) printf("%lld ",ans[j].a);
For(k,1,ans[j].cb) printf("%lld ",ans[j].b);
puts("");
}
}
}
return 0;
}
/*
2
1
12
100
100000000
*/
蛋糕
【题目描述】
今天是鲍勃的生日,爱丽丝打算做一个蛋糕送给他。 这是鲍勃的 n 岁生日,所以爱丽丝的蛋糕必须是正 n 边形。而且,鲍勃很喜 欢数字 m,所以这个蛋糕必须放在一个正 m 边形的盒子里。为了让气氛更加浪漫, 爱丽丝将在蛋糕的中心插上一根蜡烛,显然,蜡烛既在蛋糕的中心,又在盒子的 中心是最好的。 换句话说,爱丽丝应该使正 n 边形的蛋糕能被容纳在正 m 边形的盒子里,且 使其中心重合。事实上,爱丽丝已经做好了蛋糕,蛋糕是边长为 1 的正 n 边形, 现在她想知道,正 m 边形盒子的最小边长是多少。
【输入格式】
每组测试数据包含多行,以 EOF 作为文件结束,每行包括两个正整数 n 和 m。
【输出格式】
输出包含多行,每行包含一个整数,代表最小的符合条件的正 m 边形盒子的 边长,保留 4 位小数。
【样例输入 1】
4 8
【样例输出 1】
0.5412
【样例输入 2】
8 4
【样例输出 2】
2.4142
【数据范围】
对于 20%的数据,n,m≤100;
对于 40%的数据,n,m≤10000;
对于 60%的数据,n,m≤1000000;
对于 80%的数据,n,m≤100000000;
对于 100%的数据,n,m≤1000000000。
成电学长讲过的原题。然而忘了做法。
n边形外套一个半径相同的正lcm边形,lcm边形再外套一个d相同的m边形即最优解。
不会证。
卡精度,要开long double。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define pi acos(-1)
const int N=200007;
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
typedef long double db;
using namespace std;
db n,m;
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
int gcd(int a,int b) { return !b?a:gcd(b,a%b); }
LL lcm(db a,db b) { return a*b/gcd(a,b); }
#define DEBUG
int main() {
#ifdef DEBUG
freopen("cake.in","r",stdin);
freopen("cake.out","w",stdout);
#endif
while(scanf("%Lf%Lf",&n,&m)==2) {
db l=lcm(n,m);
db a=cos(pi/(db)l)/sin(pi/(db)n)*tan(pi/(db)m);
printf("%.4Lf
",a);
}
return 0;
}
Chika 的烦恼
【题目描述】
Chika 家经营着一家旅馆,她经常要帮家里的忙,有时候,她需要去清理长
满杂草的后院。具体地,后院里面的每棵草都有其生长速率(每天所能生长的高
度),在某些给定的日期,她需要把高度大于某个值 b 的杂草割掉一截,使其高
度剩余 b。(b 在每次给定的日期时不一定相同。)
她想请你帮她统计一下,每次她所割掉的草的总量是多少。
假设最开始每棵草的高度是零。
【输入格式】
第一行为两个整数 n, m,代表后院里草总共有 n 棵,以及发生的事件的总
数 m。
第二行包含 n 个整数 a1, a2, ..., an。ai (1≤i≤n)代表第 i 棵草的生长速
度为每天 ai个单位。
接下来 m 行,第 i 行包含两个整数 di, bi,代表在第 di天结束时,Chika 把
所有高度大于 bi的草的高度变成了 bi。(保证输入的 di是递增的)
【输出格式】
包含 m 行,每行一个整数,代表割掉的草的总量共有多少个单位。
【样例输入】
4 4
1 2 4 3
1 1
2 2
3 0
4 4
【样例输出】
6
6
18
0
【数据范围】
1≤n,m≤400000,
1≤ai≤106
,
1≤di≤1012
,
6
0≤bi≤1012
,
d1<d2<...<dm,
保证在每次割草时,没有草的高度会超过 2×1012
。
存在 30%的数据,n,m≤2000,
存在另外 30%的数据,n,m≤50000。
【样例解释】
天数 割之前草的高度 割之后草的高度 割掉的草的总量
1 1,2,4,3 1,1,1,1 6
2 2,3,5,4 2,2,2,2 6
3 3,4,6,5 0,0,0,0 18
4 1,2,4,3 1,2,4,3 0
线段树水题。
发现相对高度保持不变,按a建线段树,维护两个标记一个区间赋值,一个区间长多少天,区间维护最大值最小值区间和区间速度和区间速度最大值区间速度最小值。
//Achen
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
const int N=400007;
#define For(i,a,b) for(int i=(a);i<=(b);i++)
#define Rep(i,a,b) for(int i=(a);i>=(b);i--)
typedef long long LL;
typedef double db;
using namespace std;
int n,m;
LL ans;
template<typename T>void read(T &x) {
char ch=getchar(); x=0; T f=1;
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;
}
struct grass {
int id; LL v;
friend bool operator <(const grass&A,const grass&B) {
return A.v<B.v||(A.v==B.v&&A.id<B.id);
}
}g[N];
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
LL sgmx[N<<2],sgmi[N<<2],sum[N<<2],vsum[N<<2],vmx[N<<2],vmi[N<<2],lz3[N<<2],lz1[N<<2],lz2[N<<2];
void build(int x,int l,int r) {
if(l==r) { vmi[x]=vmx[x]=vsum[x]=g[l].v; return; }
build(lc,l,mid); build(rc,mid+1,r);
vmi[x]=min(vmi[lc],vmi[rc]);
vmx[x]=max(vmx[lc],vmx[rc]);
vsum[x]=vsum[lc]+vsum[rc];
}
void cover(int x,int len,LL v) {
sum[x]=len*v;
sgmi[x]=sgmx[x]=v;
lz3[x]=1; lz2[x]=0;
lz1[x]=v;
}
void gogo(int x,int t) {
sum[x]+=vsum[x]*t;
sgmi[x]=sgmi[x]+vmi[x]*t;
sgmx[x]=sgmx[x]+vmx[x]*t;
lz2[x]+=t;
}
void down(int x,int l_len,int r_len) {
if(lz3[x]) {
if(l_len) cover(lc,l_len,lz1[x]);
if(r_len) cover(rc,r_len,lz1[x]);
lz3[x]=0;
}
if(lz2[x]) {
if(l_len) gogo(lc,lz2[x]);
if(r_len) gogo(rc,lz2[x]);
lz2[x]=0;
}
}
void change(int x,int l,int r,LL b) {
if(sgmi[x]>=b) {
ans+=sum[x]-b*(r-l+1);
cover(x,r-l+1,b); return;
}
down(x,mid-l+1,r-mid);
if(sgmx[rc]>=b) change(rc,mid+1,r,b);
if(sgmx[lc]>=b) change(lc,l,mid,b);
sgmx[x]=max(sgmx[lc],sgmx[rc]);
sgmi[x]=min(sgmi[lc],sgmi[rc]);
sum[x]=sum[lc]+sum[rc];
}
#define DEBUG
int main() {
#ifdef DEBUG
freopen("grass.in","r",stdin);
freopen("grass.out","w",stdout);
#endif
read(n); read(m);
For(i,1,n) { read(g[i].v); g[i].id=i; }
sort(g+1,g+n+1);
build(1,1,n);
LL pr=0;
For(ti,1,m) {
LL d,b; ans=0;
read(d); read(b);
gogo(1,d-pr);
change(1,1,n,b);
pr=d;
printf("%lld
",ans);
}
return 0;
}
/*
4 4
1 2 4 3
1 1
2 2
3 0
4 4
*/