P7800 [COCI2015-2016#6] PAROVI 题解

读完题后可以首先发现,编号 1n 的点都是必须要选的,否则 Slavko 可以选择 2 或者 n 取得胜利。

而对于中间的数如果存在两对数 (l1,r1) (l2,r2)l1<l2r1l2 那么可以选择数 l2 取胜。

那么只有 r1>l2 时,取 l2 是无法取胜的,此时若把两对数看成一个区间,那么就可以将本题看成一个左闭右开的区间覆盖问题。

由于求方案数,考虑 dp。

预处理出来所有互质的数对,并按左区间为关键字排序。

fi,j 代表对于第 i 个区间,已经覆盖到第 j 格的方案数。

初始化:对于数对 (li,ri),如果 li=1,那么 fi,ri=1

转移:

选择这个区间:fi,max(j,ri)=fi,max(j,ri)+fi1,j(lij)

不选这个区间:fi,j=fi,j+fi1,j

答案即为 fnum,n其中 num 代表互质数对个数

复杂度约为 O(n3)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define int long long
using namespace std;
const int mod=1e9;
const int N=25;
int n,cnt,f[N*N][N];
int gcd(int x,int y)
{
	if(y==0)return x;
	return gcd(y,x%y);
}
struct node
{
	int l,r;
}a[N*N];
int cmp(node fi,node se)
{
	return fi.r>se.r;
}
signed main()
{
	freopen("parovi.in","r",stdin);
	freopen("parovi.out","w",stdout);
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
	{
		for(int j=i+1;j<=n;j++)if(gcd(i,j)==1)a[++cnt]=(node){i,j};
	}
	for(int i=1;i<=cnt;i++)
	{
		if(a[i].l==1)f[i][a[i].r]=1;
		for(int j=1;j<=n;j++)
		{
			f[i][j]+=f[i-1][j];
			f[i][j]%=mod;
			if(a[i].l<=j)f[i][max(j,a[i].r)]+=f[i-1][j],f[i][max(j,a[i].r)]%=mod;
		}
	}
	int ans=f[cnt][n];
	printf("%lld",ans);
	return 0;
}
posted @   Gmt丶Fu9ture  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示