时间:20181222-12:20:00 to 20181222-17:20:00
现场比赛(大一限定)时 L 题题目表述有误(但修正后仍无 AC)。现场无 AC 的题有 F,H,I,L(I 题现场无提交)。另有 C 题仅 3 人 AC,D 题仅 1 人 AC(均为现场,其中 C 题可能原因为题面表述不明)。
题目大意:给两个长度均为 N 数组 L 1.. n L_{1 .. n} L1..n 和 G 1.. n G_{1 .. n} G1..n,正反序比对,是否相应位置元素均有 L i ≤ G i L_i ≤ G_i Li≤Gi。
水题。代码如下:
#include
#define MAX_N (100005)
int l[MAX_N];
int main()
{
bool b,f;
int g,n,t;
scanf("%d",&t);
while(t--)
{
b=f=true;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&l[i]);
for(int i=0;i<n;i++)
scanf("%d",&g),
f&=l[i]<=g,b&=l[n-i-1]<=g;
puts(f?b?"both":"front":b?"back":"none");
}
return 0;
}
题目大意:给长度为 n 正整数列和正整数 m,判断数列中是否存在区间和为 m 倍数。
计算出前缀和数组,判断数组中是否有对 m 模相同余数的项即可。代码如下:
#include
#define MAX_M (2005)
bool a[MAX_M];
int main()
{
bool flag;
int m,n,x,s;
while(scanf("%d %d",&n,&m)==2)
{
for(int i=0;i<m;i++)
a[i]=false;
flag=false,s=0;
while(n--)
scanf("%d",&x),s=(s+x)%m,flag|=a[s],a[s]=true;
puts(flag?"YES":"NO");
}
return 0;
}
题目大意:给长度为 n 正整数列 a 1.. n a_{1 .. n} a1..n,建图如下:若 g c d ( a i , a j ) > 1 gcd(a_i, a_j) > 1 gcd(ai,aj)>1,则于点 a i a_i ai 和点 a j a_j aj 间存在一条无向边;若 a i = a j a_i = a_j ai=aj,则为同一点。求连通块数和最大连通块大小。
由于每个连通块都存在公共质因子,处理出数列中每个数的所有质因子,并查集合并点集即可。代码如下:
#include
#define MAX_N (100005)
int sp[MAX_N],st[MAX_N],sz[MAX_N];
int fnd(int x)
{
if(st[x]==x)
return x;
return st[x]=fnd(st[x]);
}
int main()
{
int ai,aj,n;
while(scanf("%d",&n)==1)
{
for(int i=0;i<MAX_N;i++)
sp[i]=-1,st[i]=i,sz[i]=0;
while(n--)
{
scanf("%d",&ai);
if(sz[fnd(ai)]>0)
continue;
aj=ai,sz[ai]=1;
for(int i=2;i*i<=ai&&aj>1;i++)
if(aj%i==0)
{
if(sp[i]!=-1)
{
sp[i]=fnd(sp[i]),st[sp[i]]=ai;
if(sp[i]!=ai)
sz[ai]+=sz[sp[i]],sz[sp[i]]=0;
}
else
sp[i]=ai;
for(;aj%i==0;aj/=i);
}
if(aj>1)
if(sp[aj]!=-1)
{
sp[aj]=fnd(sp[aj]),st[sp[aj]]=ai;
if(sp[aj]!=ai)
sz[ai]+=sz[sp[aj]],sz[sp[aj]]=0;
}
else
sp[aj]=ai;
}
ai=aj=0;
for(int i=0;i<MAX_N;i++)
if(sz[i]>0)
{
if(aj<sz[i])
aj=sz[i];
ai++,sz[i]=0;
}
printf("%d %d\n",ai,aj);
}
return 0;
}
题目大意:给 N 个点无根树,边权为 1。M 次操作,设所有点初始均为基态,每次操作两个点 a 和 b,若为基态则变为激发态,若为激发态则变为基态。操作后,激发态点数必为偶,则存在一种方案使所有激发态点两两配对,并使所有激发态点对间距离和最小。求每次操作后最小距离和。
显然,最小点对距离和方案必然路径不相交,即所有边最多通过一次(点可能多次)。若存在一种方案存在 A-C-D-F 和 B-C-D-E 两条路径(即激发态点 ABEF,边集 C-D 通过两次),则另一种方案 A-C-B 和 E-D-F 显然更优。归纳出一般规律,对于任一种方案,若某边通过偶数次则最优方案通过 0 次,若某边通过奇数次则最优方案通过 1 次。对于一次操作,相当于点 a 和点 b 间加上一条路径(由于树性质,路径唯一)。当经过一个点的路径数为偶时,该点为基态(上例中点 C 有 A-C 一、B-C 一、C-D 二、共四为偶,故为基态),否则为激发态。每次查询所有边中经过次数为奇的边数即为最小点对距离和。
可以看出,每次操作只改变一条路径上边的奇偶性。将每次操作看成查询路径 a-b 上所有边权和,并将路径 a-b 上所有边权乘以 -1,上次查询结果加上本次查询路径边权和即为本次查询结果。这样,每次操作后,边权为 -1 的边为参与点对匹配的边,边权为 1 的边为不参与点对匹配的边。如此,问题转化成维护一棵初始边权均为 1 的树,操作类型有区间乘 -1 和区间和查询,数链剖分套线段树即可。代码如下:
#include
#define MAX_N (100005)
#define MAX_2LGN (0x3FFFF)
int vdg[MAX_N];
struct E
{
int to;
E *nxt;
}edg[MAX_N+MAX_N],*fdg[MAX_N];
struct V
{
int dep,fah,gfa,siz,son;
}vtx[MAX_N];
struct SegTreeNode
{
int bl,br,fg,ky;
}stn[MAX_2LGN];
void dfs0(int n)
{
vtx[n].siz=1,vtx[n].son=0;
for(E *i=fdg[n];i!=NULL;i=i->nxt)
if(i->to!=vtx[n].fah)
{
vtx[i->to].dep=vtx[n].dep+1;
vtx[i->to].fah=n;
dfs0(i->to);
vtx[n].siz+=vtx[i->to].siz;
if(vtx[vtx[n].son].siz<vtx[i->to].siz)
vtx[vtx[n].son].gfa=vtx[n].son,
vtx[n].son=i->to;
else
vtx[i->to].gfa=i->to;
}
}
void dfs1(int n)
{
for(E *i=fdg[n];i!=NULL;i=i->nxt)
if(i->to!=vtx[n].fah&&i->to!=vtx[n].son)
dfs1(i->to);
if(vtx[n].son!=0)
vtx[vtx[n].son].gfa=vtx[n].gfa,
dfs1(vtx[n].son);
vdg[n]=++vdg[0];
}
void SegTreeBuild(int n,int l,int r)
{
stn[n].bl=l,stn[n].br=r,stn[n].fg=1;
if(l+1==r)
{
stn[n].ky=1;
return;
}
int m=(l+r+1)/2;
SegTreeBuild(n*2,l,m);
SegTreeBuild(n*2+1,m,r);
stn[n].ky=stn[n*2].ky+stn[n*2+1].ky;
}
#define SegTreeFlag(x) \
if(stn[x].fg==-1) \
{ \
stn[x].fg=-stn[x].fg; \
stn[x].ky=-stn[x].ky; \
if(stn[x].bl+1
void SegTreeModify(int n,int ql,int qr)
{
if(stn[n].bl>=ql&&stn[n].br<=qr)
{
stn[n].fg=-stn[n].fg;
SegTreeFlag(n);
return;
}
SegTreeFlag(n);
if(stn[n*2].br>ql)
SegTreeModify(n*2,ql,qr);
else
SegTreeFlag(n*2);
if(stn[n*2+1].bl<qr)
SegTreeModify(n*2+1,ql,qr);
else
SegTreeFlag(n*2+1);
stn[n].ky=stn[n*2].ky+stn[n*2+1].ky;
}
int SegTreeQuery(int n,int ql,int qr)
{
SegTreeFlag(n);
if(stn[n].bl>=ql&&stn[n].br<=qr)
return stn[n].ky;
int s=0;
if(stn[n*2].br>ql)
s+=SegTreeQuery(n*2,ql,qr);
else
SegTreeFlag(n*2);
if(stn[n*2+1].bl<qr)
s+=SegTreeQuery(n*2+1,ql,qr);
else
SegTreeFlag(n*2+1);
stn[n].ky=stn[n*2].ky+stn[n*2+1].ky;
return s;
}
int lca(int u,int v)
{
int s=0;
if(vtx[u].gfa!=vtx[v].gfa)
{
if(vtx[vtx[u].gfa].dep<vtx[vtx[v].gfa].dep)
u^=v^=u^=v;
s=SegTreeQuery(1,vdg[u],vdg[vtx[u].gfa]+1)+lca(vtx[vtx[u].gfa].fah,v);
SegTreeModify(1,vdg[u],vdg[vtx[u].gfa]+1);
}
else
{
if(vtx[u].dep<vtx[v].dep)
u^=v^=u^=v;
if(u!=v)
s=SegTreeQuery(1,vdg[u],vdg[vtx[v].son]+1),
SegTreeModify(1,vdg[u],vdg[vtx[v].son]+1);
}
return s;
}
int main()
{
int a,b,m,n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
fdg[i]=NULL;
for(int i=1;i<n;i++)
scanf("%d %d",&edg[i+n].to,&edg[i].to),
edg[i+n].nxt=fdg[edg[i].to],fdg[edg[i].to]=&edg[i+n],
edg[i].nxt=fdg[edg[i+n].to],fdg[edg[i+n].to]=&edg[i];
vtx[0].siz=vtx[1].fah=0,vtx[1].dep=1,dfs0(1);
vdg[0]=0,vtx[1].gfa=1,dfs1(1);
SegTreeBuild(1,1,n);
scanf("%d",&m);
n=0;
while(m--)
scanf("%d %d",&a,&b),
printf("%d\n",n+=lca(a,b));
}
return 0;
}
题目大意:给 n 个区间,判断是否存在相交区间。
水题。代码如下:
#include
#include
#define MAX_N (100005)
struct POINT
{
int x,y;
}itv[MAX_N+MAX_N];
bool cmp(POINT p,POINT q)
{
return p.x<q.x;
}
int stk[MAX_N];
int main()
{
bool flag;
int n;
while(scanf("%d",&n)==1)
{
for(int i=0;i<n;i++)
scanf("%d %d",&itv[i].x,&itv[i+n].x),itv[i].y=i+1,itv[i+n].y=-i-1;
std::sort(itv,itv+n+n,cmp);
flag=true,stk[0]=0;
for(int i=0;i<n+n&&flag;i++)
if(itv[i].y>0)
stk[++stk[0]]=itv[i].y;
else if(-itv[i].y==stk[stk[0]])
--stk[0];
else
flag=false;
puts(flag?"NO":"YES");
}
return 0;
}
题目大意:设方程 a 1 x 1 + a 2 x 2 + . . . . + a n x n − d y = 0 a_1x_1 + a_2x_2 + .... + a_nx_n - dy = 0 a1x1+a2x2+....+anxn−dy=0 求最小正整数 y 使得该方程有正整数解。d ≤ 40,000,n ≤ 100,1 ≤ a i a_i ai ≤ 2 ∗ 1 0 9 2*10^9 2∗109。
笔者能力所限,未能解决该问题。
题目大意:二分图最大匹配。
匈牙利算法,最大流算法均可。本题数据可能存在较大问题(过弱)。代码如下:
#include
#define MAX_K (1005)
#define MAX_N (1005)
struct E
{
int to;
E *nxt;
}edg[MAX_K+MAX_K],*fdg[MAX_N+MAX_N];
int m,mtc[MAX_N];
bool dfn[MAX_N];
bool dfs(int n)
{
dfn[n-m]=true;
for(E *i=fdg[n];i!=NULL;i=i->nxt)
if(!dfn[mtc[i->to]-m]&&(mtc[i->to]==-1||dfs(mtc[i->to])))
{
mtc[i->to]=n;
return true;
}
return false;
}
int main()
{
int k,n,t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m+n;i++)
fdg[i]=NULL;
while(k--)
scanf("%d %d",&edg[k*2].to,&edg[k*2+1].to),edg[k*2].to+=m,
edg[k*2].nxt=fdg[edg[k*2+1].to],fdg[edg[k*2+1].to]=&edg[k*2],
edg[k*2+1].nxt=fdg[edg[k*2].to],fdg[edg[k*2].to]=&edg[k*2+1];
k=0;
for(int i=1;i<=m;i++)
mtc[i]=-1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
dfn[j]=false;
if(dfs(i+m))
k++;
}
printf("%d\n",k);
}
return 0;
}
题目大意:在 N * M 棋盘上,求马由 (1, 1) 到达 (a, b) 最小步数。数据范围 1 0 18 10^{18} 1018。
笔者能力所限,未能解决该问题。
笔者的想法是,min(a, b) ≤ 3 时找规律,小范围数据暴力解决,大数据找规律。翻转使得终点位于 3 到 4 点半方向,当位于 3 到 4 点钟方向时,通过最多三次 1 点钟或 5 点钟马步和若干可计算次 2 点钟和 4 点钟马步到达;当位于 4 到 4 点半方向时,通过最多二次 2 点钟或 7 点钟马步和若干可计算次 4 点钟和 5 点钟马步到达。不过,该想法仍存在问题。
题目大意:给 n 个非负整数 x 1.. n x_{1 .. n} x1..n,将其划为三部分,设三部分数个数分别为 n 1 n_1 n1、 n 2 n_2 n2、 n 3 n_3 n3,每部分数中最大值分别为 h 1 h_1 h1、 h 2 h_2 h2、 h 3 h_3 h3,求 ( n 1 + n 3 ) ∗ m a x ( h 1 , h 3 ) + n 2 ∗ h 2 (n_1 + n_3) * max(h_1, h_3) + n_2 * h_2 (n1+n3)∗max(h1,h3)+n2∗h2 的最小值。 n 1 n_1 n1、 n 2 n_2 n2、 n 3 n_3 n3 可以为 0。
将原数列首尾相接形成数环,则原问题等价于将数环分为两部分,数个数分别为 n 1 n_1 n1、 n 2 n_2 n2,最大值分别为 h 1 h_1 h1、 h 2 h_2 h2,求 n 1 ∗ h 1 + n 2 ∗ h 2 n_1 * h_1 + n_2 * h_2 n1∗h1+n2∗h2 的最小值。令 h 1 = m a x ( x 1.. n ) h_1 = max(x_{1 .. n}) h1=max(x1..n),即第一部分包含数列中最大值,可得 h 1 ≥ h 2 h_1 ≥ h_2 h1≥h2。考虑任一种方案,第二部分为 x L 2 x_{L2} xL2 到 x R 2 x_{R2} xR2(则在数环意义上,第一部分为 x R 2 + 1 x_{R2 + 1} xR2+1 到 x L 2 − 1 x_{L2 - 1} xL2−1),对于 x L 2 − 1 x_{L2 - 1} xL2−1 和 x L 2 x_{L2} xL2 之间的关系,若有 x L 2 − 1 ≤ x L 2 x_{L2 - 1} ≤ x_{L2} xL2−1≤xL2,则将 x L 2 − 1 x_{L2 - 1} xL2−1 划给第二部分的方案显然更优(因为如此一来, n 1 n_1 n1 减一, n 2 n_2 n2 加一, h 2 h_2 h2 不变且仍小于 h 1 h_1 h1)。于是,最优方案必有如下性质: x L 2 − 1 > x L 2 x_{L2 - 1} > x_{L2} xL2−1>xL2 且 x R 2 < x R 2 + 1 x_{R2} < x_{R2 + 1} xR2<xR2+1。
搜索,每次选取数环第二部分中最大数位置,将最大数连同其左边所有数或右边所有数全部划为第一部分,更新最优解,并递归搜索下去。最优解如上性质必定会被搜索到,即使存在相同数也不影响搜索顺序(若相同数比最优解 h 2 h_2 h2 大,则相同数全部划为第一部分后必存在一颗搜索子树为最优解;若相同数不比最优解 h 2 h_2 h2 大,则在搜索相同数之前就已经搜索到最优解)。处理时通过将数列最大值循环移动至数列首部使得第二部分连续,并需 ST 表实现 RMQ 功能。代码如下:
#include
#define MAX_N (10000005)
#define MAX_2N (0x1FFFFFF)
#define INF (0x7FFFFFFFFFFFFFFFll)
#define MinLL(a,b) \
({ \
long long __tmp_a=(a),__tmp_b=(b); \
__tmp_a<__tmp_b?__tmp_a:__tmp_b; \
})
#define MaxInx(a,b) \
({ \
int __tmp_a=(a),__tmp_b=(b); \
x[__tmp_a]>x[__tmp_b]?__tmp_a:__tmp_b; \
})
int m,n,st[MAX_2N],x[MAX_N],xt[MAX_N];
long long ans;
int MaxST(int f,int l,int r,int p,int m)
{
if(l>r)
return 0;
int lt=p<<f,md=p<<f|1<<f-1,rt=p+1<<f;
if(l<=lt&&r>=rt-1)
return st[1<<m-f|p];
if(r<md)
return MaxST(f-1,l,r,p*2,m);
if(l>=md)
return MaxST(f-1,l,r,p*2+1,m);
return MaxInx(MaxST(f-1,l,r,p*2,m),MaxST(f-1,l,r,p*2+1,m));
}
void dfs(int lt,int rt)
{
if(lt==rt)
{
ans=MinLL(ans,(n-1)*(long long)x[0]+x[lt]);
return;
}
if((n-rt+lt-1)*(long long)x[0]>ans)
return;
int md=MaxST(m,lt,rt,0,m);
ans=MinLL(ans,(n-rt+lt-1)*(long long)x[0]+(rt-lt+1)*(long long)x[md]);
if(lt<md)
dfs(lt,md-1);
if(md<rt)
dfs(md+1,rt);
}
int main()
{
int a,b,mod,num,s,t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&m,&n);
xt[0]=0;
while(m--)
{
scanf("%d %d %d %d %d",&num,&s,&a,&b,&mod);
while(num--)
xt[++xt[0]]=s,s=(s*(long long)a+b)%mod;
}
for(m=0,--xt[0];xt[0]>0;m++,xt[0]>>=1);
for(int i=1;i<=n;i++)
if(xt[xt[0]]<xt[i])
xt[0]=i;
for(int i=0;i<n;i++)
x[i]=xt[(xt[0]+i-1)%n+1];
for(int i=0;i<MAX_2N;i++)
st[i]=0;
for(int i=0;i<n;i++)
st[1<<m|i]=i;
for(int i=0;i<m;i++)
for(int j=0;j<<i+1<n;j++)
st[1<<m-i-1|j]=MaxInx(st[1<<m-i|j*2],st[1<<m-i|j*2+1]);
ans=INF;
dfs(1,n-1);
printf("%lld\n",ans);
}
return 0;
}
题目大意:求 N! 的因子中有多少数恰有 75 个因子。
一个数有奇数个因子当且仅当它为完全平方数。 75 = 3 ∗ 5 ∗ 5 = 5 ∗ 15 = 3 ∗ 25 = 75 75 = 3 * 5 * 5 = 5 * 15 = 3 * 25 = 75 75=3∗5∗5=5∗15=3∗25=75,即有 75 个因子的数 X = p 1 2 ∗ p 2 4 ∗ p 3 4 X = p_1^2 * p_2^4 * p_3^4 X=p12∗p24∗p34 或 X = p 1 4 ∗ p 2 14 X = p_1^4 * p_2^{14} X=p14∗p214 或 X = p 1 2 ∗ p 2 24 X = p_1^2 * p_2^{24} X=p12∗p224 或 X = p 1 74 X = p_1^{74} X=p174( p 1 , p 2 , p 3 p_1,p_2,p_3 p1,p2,p3 均为质数且互不相同)。
3 / 2 + 3 / 4 = 1 + 0 = 1
4 / 2 + 4 / 4 = 2 + 1 = 3
5 / 2 + 5 / 4 = 2 + 1 = 3
6 / 2 + 6 / 4 = 3 + 1 = 4
15 / 2 + 15 / 4 + 15 / 8 + 15 / 16 = 7 + 3 + 1 + 0 = 11
16 / 2 + 16 / 4 + 16 / 8 + 16 / 16 = 8 + 4 + 2 + 1 = 15
27 / 2 + 27 / 4 + 27 / 8 + 27 / 16 = 13 + 6 + 3 + 1 = 23
28 / 2 + 28 / 4 + 28 / 8 + 28 / 16 = 14 + 7 + 3 + 1 = 25
77 / 2 + 77 / 4 + 77 / 8 + 77 / 16 + 77 / 32 + 77 / 64 = 38 + 19 + 9 + 4 + 2 + 1 = 73
78 / 2 + 78 / 4 + 78 / 8 + 78 / 16 + 78 / 32 + 78 / 64 = 39 + 19 + 9 + 4 + 2 + 1 = 74
4! 可提供 2 个质因子 2,6! 可提供 4 个质因子 2,16! 可提供 14 个质因子 2,28! 可提供 24 个质因子 2,78! 可提供 74 个质因子 2。
5 / 3 = 1
6 / 3 = 2
8 / 3 + 8 / 9 = 2 + 0 = 2
9 / 3 + 9 / 9 = 3 + 1 = 4
29 / 3 + 29 / 9 + 29 / 27 = 9 + 3 + 1 = 13
30 / 3 + 30 / 9 + 30 / 27 = 10 + 3 + 1 = 14
53 / 3 + 53 / 9 + 53 / 27 = 17 + 5 + 1 = 23
54 / 3 + 54 / 9 + 54 / 27 = 18 + 6 + 2 = 26
6! 可提供 2 个质因子 3,9! 可提供 4 个质因子 3,30! 可提供 14 个质因子 3,54! 可提供 24 个质因子 3。
59 / 5 + 59 / 25 = 11 + 2 = 13
60 / 5 + 60 / 25 = 12 + 2 = 14
99 / 5 + 99 / 25 = 19 + 3 = 22
100 / 5 + 100 / 25 = 20 + 4 = 24
60! 可提供 14 个质因子 5,100! 可提供 24 个质因子 5。
90 / 7 + 90 / 49 = 12 + 1 = 13
91 / 7 + 91 / 49 = 13 + 1 = 14
91! 可提供 14 个质因子 7。
当 p > 4 时,(2p)! 可提供 2 个质因子 p,(4p)! 可提供 4 个质因子 p。
打表即可。代码如下:
#include
#define MAX_N (105)
bool prime(int x)
{
if(x<2)
return false;
for(int i=2;i*i<=x;i++)
if(x%i==0)
return false;
return true;
}
int ans[MAX_N];
int main()
{
int n,s02,s04,s14,s24;
ans[0]=s02=s04=s14=s24=0;
for(int i=1;i<=100;i++)
{
ans[i]=ans[i-1];
if(i%2==0&&prime(i/2))
ans[i]+=s04*(s04-1)/2+s24,s02++;
if(i==6||i==9||i!=8&&i!=12&&i%4==0&&prime(i/4))
ans[i]+=(s02-2)*s04+s14,s04++;
if(i==16||i==30||i==60||i==91)
ans[i]+=s04-1,s14++;
if(i==28||i==54||i==100)
ans[i]+=s02-1,s24++;
if(i==78)
ans[i]++;
}
while(scanf("%d",&n)==1)
printf("%d\n",ans[n]);
return 0;
}
题目大意:给 N 个点无根树,边权为 1,求路径长为奇的路径数。
以点 1 为根建树,设 S i , 0 S_{i, 0} Si,0 为以 i 为根子树中距根长度为偶数的点数(包括根), S i , 1 S_{i, 1} Si,1 为以 i 为根子树中距根长度为奇数的点数。考虑点对 (s, t),设其最近公共祖先为 lca(s, t),则路径 s - lca(s, t) - t 和路径 s - lca(s, t) - 1 - lca(s, t) - t 长度奇偶性相同,树上任一路径均可看作经过根的长度奇偶性相同的等价路径,由奇数 = 偶数 + 奇数可知,则 S 1 , 0 ∗ S 1 , 1 S_{1, 0} * S_{1, 1} S1,0∗S1,1 即为所求。代码如下:
#include
#define MAX_N (100005)
int s[MAX_N][2];
struct E
{
int to;
E *nxt;
}edg[MAX_N+MAX_N],*vtx[MAX_N];
void dfs(int x)
{
s[x][0]=1,s[x][1]=0;
for(E *i=vtx[x];i!=NULL;i=i->nxt)
if(s[i->to][0]==0)
dfs(i->to),
s[x][0]+=s[i->to][1],
s[x][1]+=s[i->to][0];
}
int main()
{
int t,n;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
vtx[i]=NULL,s[i][0]=0;
for(int i=1;i<n;i++)
scanf("%d %d",&edg[i*2].to,&edg[i*2-1].to),
edg[i*2].nxt=vtx[edg[i*2-1].to],vtx[edg[i*2-1].to]=&edg[i*2],
edg[i*2-1].nxt=vtx[edg[i*2].to],vtx[edg[i*2].to]=&edg[i*2-1];
dfs(1);
printf("%lld\n",s[1][0]*(long long)s[1][1]);
}
return 0;
}
题目大意:给 n ( ≤ 1 0 9 ) , k ( ≤ 1000 ) , a 1.. k , f 0.. k − 1 n(≤ 10^9), k(≤ 1000), a_{1 .. k}, f_{0 .. k - 1} n(≤109),k(≤1000),a1..k,f0..k−1,已知 f n = ∑ j = 1 k a j ∗ f n − j f_n = \sum_{j=1}^k a_j*f_{n-j} fn=∑j=1kaj∗fn−j,求 f n f_n fn mod 1e9+7。
笔者能力所限,未能解决该问题。
笔者有幸参与此次比赛,无奈才疏学浅,仅 AC 二题(B 题和 K 题)。L 题开始想借矩阵快速幂之力,但矩阵乘法时间复杂度 k 3 k^3 k3 直接 TLE。J 题考场中程序已然写成,不幸代码中一个常数算错而 WA。E 题代码 WA 而检查无果,考后发现一条调试输出语句忘删。HF 题均非力所能及,直接放弃。ACG 题未加细看便直接放弃,但事实上均可做。D 题现场便想出数剖套线段树的做法,但数剖代码过长线段树长时未写而放弃。最后编写 I 题,直到考试结束都笔者都未能将 I 题编完,不过现在看来当时的贪心思路偏差较大,就算编完也只能以 WA 收尾。从此次比赛看来,HIT 藏龙卧虎,算法竞赛之路任重而道远。