======牛客多校第五场======
这场的题目好啊!
一般有规律,奇数场可能偏向数学计算,偶数场更考验玛俐码力。在本人的码力实在不足的情况下,看来更喜欢考验思维量的题目。
(成功地首次独立写出了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
=====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语言完成。
[[小型代码管理系统的实现方式]]