zoukankan      html  css  js  c++  java
  • [多校联考2021] 模拟赛2

    总结

    ( t tly,yyds!) 今天他直接碾压第二题百来分,( t A) 掉了两个题。

    怎么说呢,我觉得正是这种难度的比赛才能看得出思维能力,这种比赛的特点就是淡化套路,( t NOI) 的出题风格也确实向这方面靠近了(我觉得这套题和 ( t NOI2020space Day2) 很像),我认为 ( t tly) 巨佬是最有钻研精神的一个,我常常看到他在走廊上独自思考,而且他从来不听讲评总是自己想题,最重要的是即使这么强他也从不摸鱼,永远再挑战更高的境界。

    我在想,这也许就是所谓不忘初心吧 (...)

    还有考试策略的问题,这次我口胡了很多暴力分上去,导致最后都没有时间打。下次应该先预估比赛难度,如果像这种难度的比赛就边想边打暴力,这次第二题写动态动规直接飞黄腾达

    wsm

    题目描述

    定义两个非递减数列 (A,B) 之间的笛卡尔和数列 (C) 为任意的 ((A_i+B_j)) 排序之后得到的非递减数列。

    (T) 组数据,给定 (C) 的长度 (n)(A) 的长度 (m),问有多少对合法的 ((A,B)) 满足笛卡尔和数列为 (C),答案对 (998244353) 取模。

    (1leq Tleq 500,1leq n,mleq 10^{12},nmod m=0)

    解法

    感谢 ( t lsk) 学长的耐心讲解,他在考试时 ( t A) 了这个题 (\%\%\%)

    首先 ( t yy) 一下最后的结果是怎么样的?想象我们把 (C) 排成一个序列,然后序列 (A) 的功能是在这个序列上面打标记,(B) 的功能是平移这个标记,最后的要求是让标记覆盖所有的 (C)( t lsk) 学长的神奇转化)

    我们考虑在 (C) 的这个序列上 (dp),设 (dp(i,j)) 表示已经填满了前 (i) 个空,用了 (j)(A) 序列的方案数,那么转移考虑把前面的序列 ( t copy) 一份(因为 (B) 的作用是整体平移,所以考虑 ( t copy)),转移:

    • 考虑添加 (B) 序列中元素:$$dp(kcdot i,j)leftarrow dp(i,j)$$

    • 考虑添加 (A) 序列中元素:$$dp(kcdot i,kcdot j)leftarrow dp(i,j)$$

    边界条件是 (dp(1,1)=1),但是这样 (dp) 会有问题,如果 (S) 能转移到 (SS)(SSSS),然后 (SS) 又能转移到 (SSSS),那么显然会算多,所以我们强制第一种转移和第二种转移交替进行(状态增加一维就行)。

    但是这样写转移肯定优化不了,因为最后我们只需要求 (dp(n,m)),所以把转移写成递归的形式,由于转移要交替进行我们定义 (f,g) 两个 (dp) 数组,下面的转移一定要把条件写清哦:

    [f(n,m)leftarrow g(frac{n}{k},m) ]

    [g(n,m)leftarrow f(frac{n}{k},frac{m}{k}) ]

    现在优化的方式很唯一,就是研究转移路径,因为转移都是做的除法,所以考虑质因数分解。这里把 (frac{n}{m})(m) 质因数分解就行了,记分解出来的质因数集合分别为 (S)(T),发现第一种转移就是在 (S) 中取若干质因数,第二种转移就是在 (T) 中取若干质因数。

    那么再把题目做一个转化,有 (S,T) 两个小球集合,有大约 (20) 种颜色 (50) 个小球,问交替划分小球集合的方案数。设 (f(i))(S) 划分出 (i)非空盒子的方案数,(g(i))(T) 划分出 (i) 个非空盒子的方案数,答案可以直接合并:

    [sum_{i}f(i)cdot (g(i-1)+2g(i)+g(i+1)) ]

    上式就是交替放置,不难理解。那么现在算出 (f(i)) 就行了((g(i)) 同理算),我们知道允许空盒子的情况是特别好算的,这就是考虑每种颜色的球,然后问不定方程解的个数,就是隔板法,设 (a(i)) 表示质因数 (p_i) 的指数:

    [f(i)=prod_{j} {a(j)+i-1choose i-1} ]

    现在要求盒子非空,那么容斥回去就可以了,这里我用的是二项式反演

    [f'(i)=sum_{j=1}^i(-1)^{i-j}f(j)cdot {ichoose j} ]

    时间复杂度瓶颈在于质因数分解,我们预处理一下 (10^6) 以内的质数就能少掉一个 (log) 了,好消息是不卡常。

    小小的总结一下吧,考试时候总以为要推结论然后就没敢做。

    方法还是老方法,先分析结果有什么特点是最重要的(这个需要强大的感知能力),这道题就是直接 (dp) 然后考虑优化的一道妙妙题,优化需要强大的观察能力哦(才能观察到质因数),这道题确实没有什么套路。

    #include <cstdio>
    const int N = 105;
    const int M = 1000005;
    const int MOD = 998244353;
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int T,n,m,cnt,ans,p[M],vis[M],C[N][N],a[N],f[N],g[N];
    void init(int n)
    {
    	for(int i=2;i<=n;i++)
    	{
    		if(!vis[i]) p[++cnt]=i;
    		for(int j=1;j<=cnt && i*p[j]<=n;j++)
    		{
    			vis[i*p[j]]=1;
    			if(i%p[j]==0) break;
    		}
    	}
    	C[0][0]=1;
    	for(int i=1;i<=100;i++)
    	{
    		C[i][0]=1;
    		for(int j=1;j<=i;j++)
    			C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
    	}
    }
    void fuck(int x,int *f)
    {
    	//质因数分解 
    	a[0]=0;
    	for(int i=1;p[i]*p[i]<=x;i++)
    		if(x%p[i]==0)
    		{
    			a[++a[0]]=0;//只用计数就行了吧 
    			while(x%p[i]==0)
    				x/=p[i],a[a[0]]++;
    		}
    	if(x>1) a[++a[0]]=1;
    	//下面是容斥
    	for(int i=1;i<=50;i++) f[i]=1; 
    	for(int i=1;i<=a[0];i++)//枚举每种球
    	{
    		for(int j=1;j<=50;j++)//j个盒子里面乱几把放 
    			f[j]=f[j]*C[a[i]+j-1][j-1]%MOD;
    	}
    	for(int i=50;i>=1;i--)//高往低容斥 
    	{
    		for(int j=i-1;j>=1;j--)
    		{
    			if((i-j)&1) f[i]=(f[i]-f[j]*C[i][j])%MOD;
    			else f[i]=(f[i]+f[j]*C[i][j])%MOD;
    		}
    	}
    }
    signed main()
    {
    	freopen("wsm.in","r",stdin);
    	freopen("wsm.out","w",stdout);
    	T=read();
    	init(1e6);
    	while(T--)
    	{
    		n=read();m=read();ans=0;
    		if(n==m || m==1)
    		{
    			puts("1");
    			continue;
    		}
    		fuck(n/m,f);//对n质因数分解后容斥 
    		fuck(m,g);//对n/m质因数分解后容斥 
    		for(int i=1;i<=50;i++)
    			ans=(ans+f[i]*(2*g[i]+g[i-1]+g[i+1])%MOD)%MOD;
    		printf("%lld
    ",(ans+MOD)%MOD);
    	}
    }
    
    
  • 相关阅读:
    点击Notification之后收起通知栏
    Visual Studio常用的快捷键
    数据库语法二之外键
    数据引擎 创建表完整语法,字段类型,约束条件
    数据库 tcp协程实现并发 回调函数
    GIL以及协程
    进程,互斥锁,生产者消费者,线程
    udp协议,进程(同步,异步)
    单例模式,网络编程之tcp协议以及粘包问题
    网络编程
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14607802.html
Copyright © 2011-2022 走看看