Codeforces Round #722 (Div. 2) D. Kavi on Pairing Duty(证明和公式图解)

104 篇文章 14 订阅
70 篇文章 0 订阅

LINK

为了方便,定义 ( x , y ) (x,y) (x,y)表示 x x x点和 y y y点配对


已知第 1 1 1个点和第 x x x个点配对,第 2 2 2个点和第 y y y个点配对

考虑 y < x y<x y<x

这是不可能的,设和 x + 1 x+1 x+1这个点配对的点为 z z z( z z z可能在左边也可能在右边)

显然 ( x + 1 , z ) (x+1,z) (x+1,z)形成的弧线既不被 ( 1 , x ) (1,x) (1,x)包含,也不被 ( 2 , y ) (2,y) (2,y)包含

那么就必须满足 a b s ( x + 1 − z ) = y − 2 & & a b s ( x + 1 − z ) = x − 1 abs(x+1-z)=y-2\&\&abs(x+1-z)=x-1 abs(x+1z)=y2&&abs(x+1z)=x1

不可能同时取等号,证毕。

那么现在 y > x y>x y>x,由于长度必须和 ( 1 , x ) (1,x) (1,x)相等,所以 2 2 2只能和 x + 1 x+1 x+1配对

以此类推,我们知道 3 3 3只能和 x + 2 x+2 x+2配对, 4 4 4只能和 x + 3 x+3 x+3配对等等

如图,当 ( 1 , x ) (1,x) (1,x)配对时,一个循环节占据的点数为 2 ∗ ( x − 1 ) 2*(x-1) 2(x1)

.当 2 n % ( 2 x − 2 ) 2n\%(2x-2) 2n%(2x2)为零时,显然可以一直放这个循环节,方案数加一

.否则

①.当 2 x − 2 < 2 n 2x-2<2n 2x2<2n时肯定无解,因为最后一个循环节放不满

也就是一定存在长度和 x − 1 x-1 x1不等的配对存在,必然会和 ( 1 , x ) (1,x) (1,x)产生矛盾

②.当 2 x − 2 > = 2 n 2x-2>=2n 2x2>=2n有解,因为按照上面的放法会变成这个样子

因为此时只有一个循环节,这样放最后中间会空出一部分,点数为 2 x − 2 − 2 ∗ n 2x-2-2*n 2x22n

那么其实这个空余段被所有其他配对包含,所以是一个相同的子问题

定义 f [ i ] f[i] f[i]表示 n = i n=i n=i时的答案

那么Ⅱ部分的答案就是 ∑ i = 1 n − 1 f [ i ] \sum\limits_{i=1}^{n-1}f[i] i=1n1f[i],因为随着 x x x的变化这些空余段都可以取到

Ⅰ部分的答案就是 n n n的因子个数,记 y i n z i i yinzi_i yinzii表示 i i i的因子个数

所以得到 f [ i ] = y i n z i i + ∑ j = 1 n − 1 f [ j ] f[i]=yinzi_i+\sum\limits_{j=1}^{n-1}f[j] f[i]=yinzii+j=1n1f[j]

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
const int mod = 998244353;
int f[maxn],yinzi[maxn],sum,n;
signed main()
{
	for(int i=1;i<=1000000;i++)
	for(int j=i;j<=1000000;j+=i)
		yinzi[j]++;
	f[1] = 1, f[2] = 3; sum = 4;
	cin >> n;
	for(int i=3;i<=n;i++)
	{
		f[i] = ( sum+yinzi[i] )%mod;
		sum = ( sum+f[i] )%mod;
	}
	cout << f[n];
}
//	f[0] = 0; f[1] = 1, f[2] = 3; //f[3] = 6;
//	for(int n=3;n<=4;n++)
//	{
//	//	f[n] = 1;
//		for(int i=1;i<=2*n;i++)//第一个段长度为2 
//		{
//			//[i+1.2i]
//			if( 2*n%(2*i)==0 )	f[n] = ( f[n]+1 )%mod;
//			if( i+1<=2*n && 2*i>=2*n )
//			{
//				int ned = 2*n-(i+1);
//				int k = 2*i-2*n;
//				cout << k << endl;
//				f[n] = ( f[n]+f[k>>1] )%mod;
//			}
//		}
//		cout << endl;
//	}
//	cout << f[3] << " " << f[4] << " " << f[100];
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值