zoukankan      html  css  js  c++  java
  • CF1528B div1 Kavi on Pairing Duty

    传送门


    题意

    有2n个点,相邻两点距离相等,现在要把这些点两两匹配, 一个好的匹配满足:
    将每个匹配的两点连成一条线段, 任意两条线段要么长度一样, 要么一条线段包含另一条。
    问共有多少种不同的好的匹配
    emm..看图
    image
    A,B是合法的,C不是, 因为红色和蓝色不符合

    下面都是合法的情况
    n=2
    image
    n=3
    image


    题解

    我们考虑dp的思想, 每次往最外面加两个点
    ... -> . ... .
    我们设(f_x)表示2x个点有多少种匹配
    一种显然的情况是将最外面两个点匹配起来, 他们能包含里面所有的点, 所以肯定合法
    此时贡献为 (f_{n-1})(最外面一对匹配起来, 里面随便怎么匹配,合法就行)
    然后我们继续考虑,还有这些情况
    image
    ......
    这种情况可以归结为先让最外面若干对匹配起来, 把里面完全包住, 里面随便匹配即可
    手玩一下发现, 这种情况贡献为fn-1+fn-2+fn-3+......+f2+f1 (看完后面读者可以想想为什么没有f0)
    除了这种情况之外, 还有另一种情况: 所有线段都相等
    比如:
    image
    这种题反正就是手玩嘛, 你多画几张图就会发现
    这种情况的贡献其实就是n的约数个数
    两种情况一加就是答案了


    然后........我居然不会求约数个数啊啊啊
    但事实上对于这种,把每个数的倍数都枚举一下就可以了,调和级数啥的复杂度是O(nlogn)


    实现

    比较简单, 直接上代码

    #include <iostream>
    #include <cstdio>
    #define ll long long
    using namespace std;
    
    int read(){
    	int num=0, flag=1; char c=getchar();
    	while(!isdigit(c) && c!='-') c=getchar();
    	if(c=='-') flag=-1, c=getchar();
    	while(isdigit(c)) num=num*10+c-'0', c=getchar();
    	return num*flag;
    }
    
    const int N = 1003005;
    const ll mod = 998244353;
    ll f[N];
    
    int main(){
    	ll sum=1, ans=1, n=read();
    	for(int i=1; i<=n; i++){
    		for(int j=1; i*j<=n; j++){
    			f[i*j]++;
    		}
    	}
    	for(int i=2; i<=n; i++){
    		ans = (sum + f[i])%mod;
    		sum = (sum + ans)%mod;
    	}
    	cout << ans << endl;
    }
    
  • 相关阅读:
    好听的歌 好音乐
    dubbox编译
    [HDU3038]How Many Answers Are Wrong(并查集)
    [POJ1733]Parity game(并查集 + 离散化)
    [POJ1703]Find them, Catch them(并查集)
    [luoguP2024] 食物链(并查集)
    [luoguP3355] 骑士共存问题(二分图最大独立集)
    火星探险问题
    [CODEVS1917] 深海机器人问题(最小费用最大流)
    [CODEVS1916] 负载平衡问题(最小费用最大流)
  • 原文地址:https://www.cnblogs.com/ltdjcoder/p/15329395.html
Copyright © 2011-2022 走看看