2019.08.13【NOIP提高组】模拟 A 组 比赛总结

题目

6300. Count

http://jzoj.net/senior/#contest/show/2848/0

6301. 普及组

http://jzoj.net/senior/#contest/show/2848/1

6302. 提高组

http://jzoj.net/senior/#contest/show/2848/2


过程

昨天论坛:
我:

话说同学们要积极地打今天的T2,争取AC,这可是明天的T3

然后……
在这里插入图片描述
接着今天就爽死了o(╥﹏╥)o
看到题目的名字时,我想:“今天的题目真有意思,T2普及组绝对是送分的。”
一看T1,矩阵乘法?不对,n矩阵乘法不了。于是想了一个nk的DP,发现只能过30分,还不如打暴力。
再看T2,WTF?又是计数题?我的心态顿时就爆炸了
金属铯+水
还好,我的心理承受能力还是有的,于是我转向T3——
在这里插入图片描述
又是计数题!今天真的要爽死了!
我昨天真的把出题人给激怒了吗?

但是很快,也才10分钟嘛我的心态就恢复了。
话说,今天的数据还是挺良心的嘛!T2给出那么多个x绝对有什么含义。
接着我就发现了x=1的规律: a n s n = 2 ( n − 1 ) 2 ans_n=2^{(n-1)^2} ansn=2(n1)2
然后x是质数的情况也很快解决了: a n s n = 2 ( n − 1 ) 2 n ! ans_n=2^{(n-1)^2}n! ansn=2(n1)2n!
但是x是和数的情况我没有弄出来。
最后暴力处理x=12和x=30的情况,结果前者的表20分钟打出来了,后者的表到比赛结束也没有弄出来。

最后T1暴力0分(TLE了?)+T2找规律&打表20分+T3人口普查分(暴力居然改不出来)=23分,rank 71。
被众大佬暴踩了。。。


题解

T1

苏DL居然考场切了?太强了%%%
可以把每一个 a i a_i ai化成 p i ⋅ m + q i p_i\cdot m+q_i pim+qi的形式,然后
∑ a i = ∑ ( p i ⋅ m + q i ) = ∑ p i ⋅ m + ∑ q i \begin{aligned} \sum a_i&=\sum(p_i\cdot m+q_i)\\[2ex] &=\sum p_i\cdot m+\sum q_i \end{aligned} ai=(pim+qi)=pim+qi
s u m q = ∑ q i sumq=\sum q_i sumq=qi,显然 s u m q &lt; k ⋅ m sumq&lt;k\cdot m sumq<km s u m q ≡ n ( m o d &ThinSpace;&ThinSpace; m ) sumq\equiv n\quad(\mod m) sumqn(modm),因此 s u m q sumq sumq只有k种取值,枚举一下,容斥求答案就可以了。
至于 ∑ p i ⋅ m \sum p_i\cdot m pim这坨东西,显然有 ∑ p i = n − s u m q m \sum p_i=\cfrac{n-sumq}{m} pi=mnsumq,这就转化成了隔板问题,也很好处理。
最后把答案乘起来就可以了。

T2

YMQ大佬比赛时找到了神奇的规律:

  1. 数据中的x分解质因数后指数不超过2;
  2. 当指数等于2时,有 a n s n = n 2 a n s n − 1 − 1 2 n ( n − 1 ) 2 a n s n − 2 ans_n=n^2ans_{n-1}-\cfrac{1}{2}n(n-1)^2ans_{n-2} ansn=n2ansn121n(n1)2ansn2

第一条规律暴力做就可以了。
第二条就是观察样例3,先把每一项除去正负数的情况,得到

n 1 2 3 4 5
num 1 3 21 282 6210

发现第 i 项貌似是第 i-1 项× i 2 i^2 i2,于是相减,得

n 1 2 3 4 5
i 2 − n u m i − 1 i^2-num_{i-1} i2numi1 - 1 6 54 840

然后发现第 i 项剩余的数是第 i-2 项的倍数诶!
结论就得出了。

看到这些,你是否与我有同感:

YMQ大佬太强了!找规律这种东西,真不是我们正常人能做的。
或许可以学习吕乐大佬,用电脑暴力枚举方程式的各项系数。

指数里可能有二。
又因为指数可能有2,因此可能的系数有1,2,3,6,1/2,1/3,1/6等。
然后也不一定时i的某次方,可能涉及i-1或更多。
然而我试到:“f[i]与f[i-1],f[i-2]有关” 时已经搞定了。
f [ i ] = a ∗ i b ∗ ( i − 1 ) c ∗ f [ i − 1 ] + d ∗ i e ∗ ( i − 1 ) f ∗ f [ i − 2 ] ; f[i]=a*i^b*(i-1)^c*f[i-1]+d*i^e*(i-1)^f*f[i-2]; f[i]=aib(i1)cf[i1]+die(i1)ff[i2];
暴力枚举abcdef,暴力尝试乘除,正负。
最后发现
a=1;
b=2;
c=0;
d=-0.5;
e=1;
f=2;

花式碾压正解。
由于质因数分解可能会T飞,x又已经给出了,这不就是出题人提示我们要打表吗?
然后我就打了表了。。。
注意:这里的表指的不是答案,而是各个数有多少个指数为1的质因子,多少个指数为2的质因子。
结果发现CJY没打表比我快了500ms+
TM的害我打了30分钟的表!
在这里插入图片描述


T3

由于这题要求最长下降子序列的长度小于等于2,因此可以转变为求2个最长不下降子序列
考虑求前缀最大值,显然第一个序列中的每一个数的前缀都比前一个数的要大,而对于剩余的数也有合法的排列。

因此问题就可以转变成在一个n*n格子图中,求(1,1)到(n,n)的合法路径个数。
可以分类讨论一下:

  1. x ≤ y x\leq y xy时,问题就是求经过点(x,y)的合法路径方案;
  2. 否则,问题就是求经过点(y,x)的合法路径方案。

题解是这样说的:

分情况讨论:

  • y ≥ x,那么该点一定在前缀max上。考虑反证,若其没有对前缀max产生贡献,那么x前面一定有一个大于y的数,同时x后面没有小于y的数,否则存在长度为3的下降子序列,也就是所有小于y 的数都在x之前,那么至少需要1 + y − 1 = y个位置,而y ≥ x > x − 1,x前面的位置不够,矛盾
  • y < x,那么该点一定不对前缀max产生贡献。这是显然的
  • 对于y < x的情况,考虑A的逆置换 A − 1 [ A i ] A^{−1}[A_i] A1[Ai] = i,可以转换成另一 种情况,也就是说只要考虑y ≥ x的情况
  • 那么什么路径是不合法的呢?由于我们求的是前缀最大值,且元素两两不相等,因此凡是触碰到直线y=x-1的路径都是不合法的。

不合法的A→B的路径必定是经过直线y=x-1的,我们把与直线相交后的路径关于直线对称,如下图所示:
图片名称
蓝色的即为对称后的路径,这样就能方便处理不合法的方案了。
最后答案显然是 (1,1)→(x,y)的合法+(x,y)→(n,n)的合法方案。(如果x>y就要交换x,y)

但是我发现我太菜了,连(x1,y1)→(x2,y2)的方案都不会算。
还好ZJJ大佬教了我方法:由于有x2-x1+y2-y1的总路径,向右的有x2-x1条,因此方案就是
( x 2 − x 1 + y 2 − y 1 x 2 − x 1 ) \begin{pmatrix} x2-x1+y2-y1 \\ x2-x1 \\ \end{pmatrix} (x2x1+y2y1x2x1)

然后就可以了。


CODE

T1

#include<cstdio>
using namespace std;
#define ll long long
#define P 998244353
#define N 10000005
ll inv[N],f[N];
inline ll C(ll n,ll m)
{
    
    
	if(n<m) return 0;
	ll s=inv[m],i;
	for(i=n-m+1;i<=n;i++) s=i%P*s%P;
	return s;
}
inline ll calc(ll n,ll m){
    
    return n<m?0:f[n]*inv[m]%P*inv[n-m]%P;}
int main()
{
    
    
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	ll n,m,k,ans=0,sum,i,t,j;
	scanf("%lld%lld%lld",&n,&m,&k);
	inv[0]=inv[1]=f[0]=f[1]=1;
	for(i=2;i<N;i++) inv[i]=inv[P%i]*(P-P/i)%P;
	for(i=2;i<N;i++) inv[i]=inv[i]*inv[i-1]%P,f[i]=f[i-1]*i%P;
	for(sum=n%m;sum<=k*m;sum+=m)
	{
    
    
		for(i=t=0,j=1;i<=k;i++,j=-j)
			t=(t+P+j*calc(k,i)*calc(sum-i*(m-1)-1,k-1)%P)%P;
		ans=(ans+t*C((n-sum)/m+k-1,k-1)%P)%P;
	}
	printf("%lld\n",ans);
	return 0;
}

T2

#pragma GCC optimize("fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("Ofast")
#include<cstdio>
using namespace std;
#define ll long long
#define mod 998244353
#define N 5000005
ll f[N],fac[N],g[N],one,two;char ch;
inline char gc()
{
    
    
	static char buf[500000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,500000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(ll &x)
{
    
    
	while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline ll pow(ll x,ll y)
{
    
    
	ll s=1;
	while(y)
	{
    
    
		if(y&1) s=s*x%mod;
		x=x*x%mod,y>>=1;
	}
	return s;
}
inline void judge(ll x)
{
    
    
	switch(x)
	{
    
    
		case 1:						one=0,two=0;break;
		case 12:					one=1,two=1;break;
		case 30:					one=3,two=0;break;
		case 147203573614806055:	one=5,two=0;break;
		case 371216956151518818:	one=6,two=0;break;
		case 834586893457709917:	one=4,two=0;break;
		case 1147387575560213988:	one=3,two=7;break;
		case 608358758975305374:	one=3,two=3;break;
		case 710701671428663075:
		case 714115052266263644:
		case 979573735390975739:
		case 640807389338647549:	one=2,two=3;break;
		case 598480316906172486:	one=3,two=3;break;
		case 203522456999371050:	
		case 421206431991626060:	one=2,two=4;break;
		case 595630806517176908:	one=2,two=3;break;
		case 573010858348910652:	one=3,two=3;break;
		case 812626144076193076:	one=2,two=4;break;
	}
}
int main()
{
    
    
	freopen("pj.in","r",stdin);
	freopen("pj.out","w",stdout);
	ll t,x,n,i,j;
	read(x),read(t);
	judge(x);
	f[1]=1,f[2]=3,fac[1]=1;
	for(i=2,g[1]=1,j=0;i<N;j=(i-1)*(i-1),i++)
		g[i]=g[i-1]*pow(2,(i-1)*(i-1)-j)%mod,fac[i]=fac[i-1]*i%mod;
	for(i=3;i<N;i++)
		f[i]=(i*i%mod*f[i-1]+mod-i*(i-1)/2%mod*(i-1)%mod*f[i-2]%mod)%mod;
	while(t--)
	{
    
    
		read(n);
		printf("%lld\n",pow(f[n],two)*pow(fac[n],one)%mod*g[n]%mod);
	}
	return 0;
}

T3

#pragma GCC optimize("fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-std=c++14"
#pragma GCC target("sse3","sse2","sse")
#pragma GCC optimize("Ofast")
#include<cstdio>
using namespace std;
#define ll long long
#define mod 1000000007
#define N 20000005
ll fac[N],inv[N];
char ch;
inline char gc()
{
    
    
	static char buf[1000000],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
    
    
	while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline ll C(ll n,ll m){
    
    return fac[n]*inv[m]%mod*inv[n-m]%mod;}
inline ll calc(int x1,int y1,int x2,int y2)
{
    
    return (C(x2-x1+y2-y1,x2-x1)+mod-C(y2+1-x1+x2-1-y1,y2+1-x1))%mod;}
int main()
{
    
    
	freopen("tg.in","r",stdin);
	freopen("tg.out","w",stdout);
	int t,n,x,y,i;
	fac[0]=fac[1]=inv[0]=inv[1]=1;
	for(i=2;i<N;i++) inv[i]=inv[mod%i]*(mod-mod/i)%mod,fac[i]=fac[i-1]*i%mod;
	for(i=2;i<N;i++) inv[i]=inv[i-1]*inv[i]%mod;
	read(t);
	while(t--)
	{
    
    
		read(n),read(x),read(y);
		if(x>y) x^=y,y^=x,x^=y;
		printf("%lld\n",calc(1,1,x,y)*calc(x,y,n,n)%mod);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/99479970
今日推荐