2019.08.17【NOIP提高组】模拟 B 组 dfs、枚举+递推+计算几何

21 篇文章 0 订阅
14 篇文章 0 订阅

0 粉刷(paint)

鸡腿想到了一个很高(sha)明(bi)的问题,墙可以看作一个N*M的矩阵,有一些格子是有污点的。现在鸡腿可以竖着刷一次,覆盖连续的最多C列,或者横着刷一次,覆盖连续的最多R行。现在鸡腿把墙上的情况告诉你,请你告诉鸡腿最少要刷多少次才能刷干净!

对于50%的数据1≤N,M≤5;

对于100%的数据1≤N,M,R,C≤15。


由于数据只有15,就直接枚举。。。

枚举行的粉刷情况,当行的粉刷情况确定后,列的粉刷次数是不变的,可以直接计算
所以就搜出所有行的粉刷情况,算出分别对应的粉刷次数,更新答案

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,m,r,c,ans=2000;
int a[20][20];
int h[20],l[20];

void dfs(int k,int s){
	if (k>n){
		for (int i=1;i<=m;i++)
			l[i]=0;
		for (int i=1;i<=n;i++)
		if (h[i]==0)
			for (int j=1;j<=m;j++)
			if (a[i][j]==1) l[j]=1;
		for (int i=1;i<=m;i++)
		if (l[i]){
			i=i+c-1;
			s++;
		}
		if (ans>s) ans=s; 
		return;
	}
	for (int i=k;i<=n;i++)
	if (h[i]==0){
		for (int j=i;j<min(i+r,n+1);j++)
			h[j]=1;
		dfs(i+r,s+1);
		for (int j=i;j<min(i+r,n+1);j++)
			h[j]=0;
	}
	dfs(n+1,s);
}

int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		char ch[20];
		scanf("%s",ch+1);
		for (int j=1;j<=m;j++)
		if (ch[j]=='X') a[i][j]=1;
	}
	scanf("%d%d",&r,&c);
	dfs(1,0);
	printf("%d",ans);
}

1 运算符(calc)

鸡腿想到了一个很高(sha)明(bi)的运算符,那就是’!’,没错就是感叹号。他给了如下的定义:

1、n!k = n!(k-1) * (n-1)!k (n> 0 and k > 0)

2、n!k = 1 (n = 0)

3、n!k = n (k = 0)

现在鸡腿告诉你n和k你能告诉他n!k的不同约数个数有多少个吗?只要对1,000,000,009取模就可以了哦!

对于30%的数据0 <n ≤ 10, 0 <k ≤ 10;

对于100%的数据0 <n ≤ 1000, 0 <k ≤ 100。


先考虑求 n ! k n!k n!k的递推式: f [ n ] [ k ] = f [ n − 1 ] [ k ] ∗ f [ n ] [ k − 1 ] f[n][k]=f[n-1][k]*f[n][k-1] f[n][k]=f[n1][k]f[n][k1]
既然是乘法,那么如果我们分别分解 f [ n − 1 ] [ k ] f[n-1][k] f[n1][k] f [ n ] [ k − 1 ] f[n][k-1] f[n][k1]的约数个数,再直接相加,即可得到对于每个 f [ i ] [ j ] f[i][j] f[i][j]每种不同质因数的个数

f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示 n = i , k = j 时,第k个质因子的数量

最后把 f [ n ] [ k ] [ i ] f[n][k][i] f[n][k][i]+1相乘即可

#include <cstdio>

using namespace std;

const long long mod=1000000009;
int n,k;
long long ans;
int f[1005][105][170];
long long c[1005];
int a[1005],p[1000],b[1005];

void prin(){
	for (int i=2;i<=n;i++){
		if (b[i]==0) p[++p[0]]=i,c[i]=1;
		for (int j=1;i*p[j]<=n&&j<=p[0];j++){
			b[i*p[j]]=1;
			if (i%p[j]==0) break;
		}
	}
}

int main(){
	scanf("%d%d",&n,&k);
	prin();
	for (int i=1;i<=n;i++){
		int x=i;
		for (int j=1;j<=p[0]&&x>1;j++)
		if (x%p[j]==0){
			while (x%p[j]==0&&x>1){
				x/=p[j];
				f[i][0][j]++;
			}
		}
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=k;j++)
			for (int l=1;l<=168;l++)
				f[i][j][l]=(f[i-1][j][l]+f[i][j-1][l])%mod;
	ans=1;
	for (int i=1;i<=p[0];i++)
	ans=(long long)(f[n][k][i]+1)*ans%mod;
	printf("%lld",ans);
}

2 倾斜的线

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


有一个很详细的题解,配有高清大图,看了图就懂了!(乱说的)

浅谈一类平面点对斜率最值问题

讲了斜率最大值、坐标变换下的斜率最大值

#include <cstdio>
#include <algorithm>
#include <cmath>

using namespace std;

long double k,mi;
long long n,p,q,ans;
struct cv{
	long long x,y;
}a[200006];

bool comp(cv a,cv b){
	return a.x*p-a.y*q<b.x*p-b.y*q;
}

long long gcd(long long a,long long b){
	if (b==0) return a;
	return gcd(b,a%b);
}

long long _gcd(long long a,long long b){
	if (a<b) swap(a,b);
	return gcd(a,b);
}

int main(){
	freopen("slope.in","r",stdin);
	freopen("slope.out","w",stdout);
	scanf("%lld%lld%lld",&n,&p,&q);
	k=(long double)p/q;
	for (int i=1;i<=n;i++)
		scanf("%lld%lld",&a[i].x,&a[i].y);
	sort(a+1,a+1+n,comp);
	mi=(long double)(a[1].y-a[2].y)/(a[1].x-a[2].x),ans=1;
	for (int i=2;i<n;i++){
		long double xie=(long double)(a[i].y-a[i+1].y)/(a[i].x-a[i+1].x);
		if (fabs(xie-k)<fabs(mi-k)){
			mi=xie;
			ans=i;
		}
	}
	long long g=_gcd(a[ans].y-a[ans+1].y,a[ans].x-a[ans+1].x);
	printf("%lld/%lld",(a[ans].y-a[ans+1].y)/g,(a[ans].x-a[ans+1].x)/g);
}

你对我的虚伪让我的心受到太大的痛苦了,我很难忘记。——摘自贝多芬给侄子的信

=你好虚伪
此名人名言适用于各大表情包

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值