2019.08.17【NOIP提高組】模擬 B 組 dfs、枚舉+遞推+計算幾何

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!kn!k的遞推式:f[n][k]=f[n1][k]f[n][k1]f[n][k]=f[n-1][k]*f[n][k-1]
既然是乘法,那麼如果我們分別分解f[n1][k]f[n-1][k]f[n][k1]f[n][k-1]的約數個數,再直接相加,即可得到對於每個f[i][j]f[i][j]每種不同質因數的個數

f[i][j][k]f[i][j][k]表示 n = i , k = j 時,第k個質因子的數量

最後把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);
}

你對我的虛僞讓我的心受到太大的痛苦了,我很難忘記。——摘自貝多芬給侄子的信

=你好虛僞
此名人名言適用於各大表情包

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章