======牛客多校第五场====== 这场的题目好啊! 一般有规律,奇数场可能偏向数学计算,偶数场更考验玛俐码力。在本人的码力实在不足的情况下,看来更喜欢考验思维量的题目。 (成功地首次独立写出了Prim算法/*优先队列优化*/——然而什么也没有发生/*只过了10%样例*/) =====D===== 因为轮换不影响,不妨在纸上按照圆形排序整个序列,找规律会发现其实就是一个简单的最长上升子序列。DP就完事了。 (和弦转位的背景还挺有趣的) #include #include int j, s, n, t, a[100001], b[100001], ans = 0; int main() { scanf("%d",&n); a[0]=-1000000; int i; for(i=1;i<=n;i++) { scanf("%d", &b[i]); b[i + 2 * n] = b[i + n] = b[i]; } int j; for(j = 0; j < n; j++) { s = 0; memset(a, 0, sizeof(a)); for(i = 0 + j; i < n + j; i++) { t = b[i + 1]; if(t > a[s]) a[++s] = t; else { int l = 1, h = s, m; while(l <= h) { m = (l + h) / 2; (t > a[m])?(l = m + 1):(h = m - 1); } a[l] = t; } } ans =(ans>s)?ans:s; } printf("%d\n",n-ans); } =====E===== 我们队是用Java过的。本来想写个高精度,奈何不会写,奈何有这样取巧的方法。 我还考虑要不要存入set的时候保证互素,使得高精度只需FFT就行了——后来发现Java竟然可以完美避过。马佬看来之前用过BigInteger类,我还是第一次听说。 为什么不写Python呢?因为编程类的专业课有Java,却没有Python,导致我能看懂与维护Java,但是还完全不会Python……虽然都是面向对象。 (这样看来,C++的面向对象就是zhazha——元首) import java.math.BigInteger; import java.util.HashSet; import java.util.Scanner; public class Main { static BigInteger[] a = new BigInteger[100005]; static boolean[] vis = new boolean[100005]; int n; public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); for (int i = 1; i < n + 1; i++) { int temp = sc.nextInt(); a[i] = BigInteger.valueOf(temp); } sc.close(); int cnt; BigInteger t; HashSet ans = new HashSet<>(); for (int i = 1; i < n + 1; i++) { if (vis[i]) { continue; } vis[i] = true; t = BigInteger.valueOf(i); cnt = 1; while (!a[t.intValue()].equals(BigInteger.valueOf(i))) { vis[a[t.intValue()].intValue()] = true; t = a[t.intValue()]; cnt++; } ans.add(BigInteger.valueOf(cnt)); } BigInteger ans1 = BigInteger.valueOf(1); for (BigInteger e : ans) { BigInteger gcd = ans1.gcd(e); ans1 = ans1.multiply(e.divide(gcd)); } System.out.println(ans1); } } 看了标程,用C++补一补题。 #include #include using namespace std; int ww; int n, p[100010]; map fac; int solve(int pos) { int cnt = 0; while(p[pos]) { int nxt = p[pos]; p[pos] = 0; pos = nxt; ++cnt; } return cnt; } void factor(int x) { int i; for(i = 2; i*i <= x;++i) { if( x % i == 0 ) { int cnt = 0; while(x % i == 0) { x /= i; ++cnt; } fac[i] =max(fac[i], cnt); } } if(x != 1) { fac[x] =max(fac[x], 1); } } int num[100010],len; void multiply(int x) { int c = 0; int i; for(i = 0; i < len; ++i) { long long tmp = (long long)x * num[i] + c; num[i] = int(tmp % 1000000); c = int(tmp / 1000000); } if( c ) { num[len++] = c; } } int main() { ww = scanf("%d", &n); int i; for(i = 1; i <= n; ++i) { ww = scanf("%d", p+i); } for(i = 1; i <= n; ++i) { if(p[i]) { factor(solve(i)); } } num[0] = 1, len = 1; map::iterator it; for(it = fac.begin(); it != fac.end(); ++it) { int now = 1; while(it->second--) { now *= it->first; } multiply(now); } for(i = len-1; i >= 0;--i) { if(i==len-1) { printf("%d",num[i]); } else { printf("%06d",num[i]); } } puts(""); return 0; } =====F===== 啥都不说,胡佬厉害!打印图形这种足以证明编程水平: #include #include int a[105]; int b[105]; int c[105]; int main() { int n, max1 = 0; scanf("%d",&n); int i; for(i=0;ia[i])?max1:a[i]; } for(i=0;i =====I===== 水。 #include int main() { printf("0.666667"); return 0; } =====B===== 以下是补题。 看了标程。DFS的思路和我一模一样,但是后面最小生成树没有用Prim,而是选择了类似于Kruskal或者其他的优化方法。 #include #include #include using namespace std; int fd(int N, int* A, int M, int* B, int K) { if(N==0||M==0) { return 1<>K-1)|1)<>K-1)|1)<> (K-1))|1) << (K-1)) - A; if(X==0 || X==N) { return solve(N, A, K-1); } return (1ll << (K-1)) + fd(X, A, N-X, A+X, K-1) + solve(X, A, K-1)+solve(N-X, A+X, K-1); } vector > G[202020]; int N, A[202020]; bool vis[202020]; void dfs(int x) { vis[x] = 1; vector >::iterator e; for(e=G[x].begin();e!=G[x].end();e++) { if(!vis[e->first]) { A[e->first] = A[x] ^ e->second; dfs(e->first); } } } int main() { scanf("%d", &N); int i; for(i = 1; i < N; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); G[u].push_back(make_pair(v,w)); G[v].push_back(make_pair(u,w)); } A[0] = 0; dfs(0); sort(A, A+N); N =unique(A, A+N) - A; printf("%lld\n", solve(N, A, 30)); return 0; } =====C===== 比赛的时候没有看这道题,后来看了题解,才发现这是一道难得的生成函数的题目。 (好题啊) ====题目==== W先生正在写序列。如果他写两个长度为K的正整数序列A和B满足: $$\sum_{i=1}^K a_i=N$$ $$\sum_{i=1}^K b_i=M$$ 他会得到: $$P=\prod_{i=1}^K \min(a_i,b_i)$$ 积分。 你想知道他能写的所有可能的序列的总分之和。 ====输入输出描述==== 输入第一行包含一个整数T(1≤T≤100),表示T个测试用例。 接下来的T行每行包含三个整数NMK(1≤N,M≤10^6,1≤K≤min(N,M))。 输出答案mod 998244353。 ====做法==== 考虑生成函数。我们知道等比数列求和: $$\frac{1}{1-x}=\sum_{i=0}^{\infty} x^i$$ 考虑x和y的无限大系数矩阵(类比第一象限附带正坐标轴整点)。那么全1矩阵就是: $$\frac{1}{(1-x)(1-y)}$$ 对角矩阵就是: $$\frac{1}{1-xy}$$ 乘在一起,再平移一下,就是: $$f(x,y)=\frac{xy}{(1-x)(1-y)(1-xy)}=\sum_{i=0}^{\infty} \sum_{j=0}^{\infty} \min(i,j)x^iy^j$$ 二元多项式f的K次幂,各项系数的含义是什么呢?对于f^K中的某一项x^Ny^M,一定由之前的K个f中的各项系数贡献而来。 首先,在之前的K个f中,x的各个幂次和是N,y的各个幂次和是M。 其次,每一个项中的系数都是x和y的最小值,共有K个乘在一起。 最后,还要对全体合法情况求和,不重不漏。 因此,所求的答案就是多项式: $$\frac{x^Ky^K}{{(1-x)}^K{(1-y)}^K}\frac{1}{{(1-xy)}^K}$$ 之中x^Ny^M前的系数。即多项式: $$\frac{1}{{(1-x)}^K}\frac{1}{{(1-y)}^K}\frac{1}{{(1-xy)}^K}$$ 之中x^{N-K}y^{M-K}前的系数。 我们希望,将“对角线”(1/(1-xy))^K的各项系数全部列出来,再乘上两个方向1/(1-x)^K和1/(1-y)^K,补到N-K和M-K。那么这就需要K次方与组合数的知识: $$\frac{1}{(1-x)^K}=\sum_{i=0}^{\infty} C_{K-1+i}^{K-1}x^i$$ $$\frac{1}{{(1-x)}^K}\frac{1}{{(1-y)}^K}\frac{1}{{(1-xy)}^K}=\left(\sum_{i=0}^{\infty} \sum_{j=0}^{\infty} C_{K-1+i}^{K-1}C_{K-1+j}^{K-1}x^iy^j\right)\left(\sum_{s=0}^{\infty} C_{K-1+s}^{K-1}{(xy)}^s\right)$$ 由于在xy项中指数相等,在x^{N-K}y^{M-K}里面的贡献,差值必然由前面来提供。因此多项式中x^{N-K}y^{M-K}项前的系数为: $$\sum_{t=0}^{\min(N,M)-K} C_{K-1+t}^{K-1}C_{N-1-t}^{K-1}C_{M-1-t}^{K-1}$$ 为所求答案。 ====代码==== #include #define mod 998244353 int fac[2020202],ffac[2020202]; int C(int n,int m) { return ((1ll*fac[n]*ffac[m])%mod*ffac[n-m])%mod; } int qpow(int n,int k) { int ret=1; while(k) { if(k&1) { ret=(1ll*ret*n)%mod; } n=(1ll*n*n)%mod; k/=2; } return ret; } void init() { fac[0]=1; int i; for(i=1;i<=2e6;i++) { fac[i]=(1ll*fac[i-1]*i)%mod; } ffac[2000000]=qpow(fac[2000000],mod-2); for(i=2e6;i>=1;i--) { ffac[i-1]=(1ll*ffac[i]*i)%mod; } } int main() { init(); int T; scanf("%d",&T); while(T--) { int N,M,K; scanf("%d%d%d",&N,&M,&K); int ans=0; int i; for(i=0;i<=(N=mod)?mod:0; } printf("%d\n",ans); } return 0; } =====J===== 有趣的计算几何。简单改了改标程,接下来基本可以简化成为C代码了。 #include #include #include #define pi acos((long double)-1) #define eps 1e-11 long double aabs(long double x) { return (long double)(x>0?x:(-x)); } struct dn { long double x,y; }; struct dn operator+(struct dn u,struct dn v) { return(struct dn){u.x+v.x,u.y+v.y}; } struct dn operator-(struct dn u,struct dn v) { return(struct dn){u.x-v.x,u.y-v.y}; } struct dn operator*(long double u,struct dn v) { return(struct dn){u*v.x,u*v.y}; } struct dn operator/(struct dn u,long double v) { return(struct dn){u.x/v,u.y/v}; } long double operator/(struct dn u,struct dn v) { return u.x*v.y-v.x*u.y; } long double operator*(struct dn u,struct dn v) { return u.x*v.x+u.y*v.y; } long double dis(struct dn o) { long double temp=o.x*o.x+o.y*o.y>0?o.x*o.x+o.y*o.y:0; return sqrt(temp); } struct dn dd(long double o) { return(struct dn){cos(o),sin(o)}; } struct dn g[5]; int top; void swap(struct dn *a,struct dn *b) { struct dn temp=(*a); (*a)=(*b); (*b)=temp; } void sswap(long double *a,long double *b) { long double temp=(*a); (*a)=(*b); (*b)=temp; } int jd(struct dn o1,long double r1,struct dn o2,long double r2,struct dn p,struct dn q,struct dn *u,struct dn *v) { top=0; struct dn o=(o1-p)*(q-p)*(q-p)/((q-p)*(q-p))+p; if(dis(o-o1)r1+eps||dis(g[i]-o2)>r2+eps) { ok=1; } if((g[i]-p)*(q-p)<-eps) { ok=1; } if(ok) { swap(&g[i],&g[top-1]); top--; i--; } } if(top>0) { *u=g[0]; } if(top>1) { *v=g[1]; } if(top==2&&((*u)-p)*(q-p)>((*v)-p)*(q-p)) { swap(&(*u),&(*v)); } return top; } long double arc(struct dn o,long double r,struct dn u,struct dn v) { long double w=(v-o)*(u-o)/r/r; w=(long double)(w>(-1)?w:(-1)); w=(long double)(w<1?w:1); if((o-u)/(v-u)>0) { return 0.5*acos(w)*r*r-0.5*aabs((v-o)/(u-o)); } else { return pi*r*r-0.5*acos(w)*r*r+0.5*aabs((v-o)/(u-o)); } } long double ar(struct dn o1,long double r1,struct dn o2,long double r2,struct dn u,struct dn v,int www) { if(dis(o2-o1)eps||(0.5*(d1+d2)-u)/(v-u)>-eps&&(v-u)*(d2-d1)>0) { return arc(o2,r2,u,v); } else { return aa-arc(o2,r2,v,u); } } if((u-d1)/(d2-d1)>-eps&&(v-d1)/(d2-d1)>-eps) { if((0.5*(d1+d2)-u)/(v-u)>eps||(0.5*(d1+d2)-u)/(v-u)>-eps&&(v-u)*(d1-d2)>0) { return arc(o1,r1,u,v); } else { return aa-arc(o1,r1,v,u); } } if((u-d1)/(d2-d1)>-eps) { return arc(o1,r1,u,d1)+arc(o2,r2,d1,v)+0.5*aabs((u-d1)/(v-d1)); } else { return arc(o1,r1,d2,v)+arc(o2,r2,u,d2)+0.5*aabs((u-d2)/(v-d2)); } } long double cc(long double p,long double q,struct dn o1,long double r1,struct dn o2,long double r2) { if(dis(o1-o2)>r1+r2-eps) { return 0; } if(r1>r2) { swap(&o1,&o2); sswap(&r1,&r2); } if(r1eps) { return aa; } else { return 0; } } if(ok1) { aa-=ar(o1,r1,o2,r2,u2,u1,0); } if(ok2) { aa-=ar(o1,r1,o2,r2,v1,v2,0); } return aa; } } int main() { int t=100000; scanf("%d",&t); int tt; for(tt=1;tt<=t;tt++) { double a,a1,a2,z1,z2,r1,r2; a=rand()%89+1; a1=rand()%360; a2=rand()%360; z1=rand()%2001; z2=rand()%2001; r1=rand()%2001; r2=rand()%2001; scanf("%lf%lf%lf%lf%lf%lf%lf",&a,&a1,&a2,&z1,&z2,&r1,&r2); a2=a2-a1+360; if(a2>=360) { a2-=360; } a1=0; if(a2>180) { a2=360-a2; } a=sin(a/180*pi); long double ans=0; ans+=cc(0,a2/180*pi*a,z2*dd(a2/180*pi*a),r2,z1*dd(0),r1); ans+=cc(0,(180-a2)/180*pi*a,z2*dd(0),r2,z1*dd(-a2/180*pi*a),r1); ans+=cc(0,a2/180*pi*a,z2*dd(-(180-a2)/180*pi*a),r2,z1*dd(pi*a),r1); ans+=cc(0,(180-a2)/180*pi*a,z2*dd(pi*a),r2,z1*dd((180-a2)/180*pi*a),r1); printf("%.30f\n",(double)ans); } } =====K===== 这又是一个大作业题目了。没想到竟然可以简单地用C语言完成。 [[小型代码管理系统的实现方式]]