Day 17
85
T1
Description
鸡腿想到了一个很高(sha)明(bi)的问题,墙可以看作一个N*M的矩阵,有一些格子是有污点的。现在鸡腿可以竖着刷一次,覆盖连续的最多C列,或者横着刷一次,覆盖连续的最多R行。现在鸡腿把墙上的情况告诉你,请你告诉鸡腿最少要刷多少次才能刷干净!
Input
第1行,输入俩正整数N,M。
第2到N+1行,每行一个长度为M的字符串,每个字符可能是’.’表示干净的,或者’X’表示这个格子有污点。
第N+2行,输入俩正整数表示R和C。
Output
输出一行一个整数,表示鸡腿最少要刷几次。
Sample Input
输入1:
1 9
XXXXXXXXX
2 3
输入2:
11 14
XXX…XXX…XXX.
.X…X…X…X
.X…X…X…X
.X…X…X…X
.X…XXX…XXX.
…
…XX…XXX…
…X…X…
…X…XXX…
…X…X…
…XXX…XXX…
1 2
Sample Output
输出1:
1
输出2:
7
Data Constraint
对于50%的数据1≤N,M≤5;
对于100%的数据1≤N,M,R,C≤15。
Solution
80pts
对于每个脏点,枚举是横着清除还是竖着清除,dfs即可。
100pts
枚举横着清除哪些横行,再处理竖列,统计答案。
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef pair<int, int> p;
const int N = 16;
const int INF = 0x3f3f3f3f;
int n,m,r,c,ans=INF;
bool a[N][N];
bool dox[N],doy[N];
char read(){
char ch=getchar();
while(ch!='.' && ch!='X'){
ch=getchar();
}
return ch;
}
int cal(){
int res=0;
bool flag=0;
int last=0,left=c;
for(int i=1; i<=m; i++){
if(doy[i]==1){
if(!flag){
flag=1;
res++;
last=i;
left--;
}
else{
if(last==i-1){
if(left==0){
left=c-1;
res++;
}
else{
left--;
}
last++;
}
else{
res++;
left=c-1;
last=i;
}
}
}
}
return res;
}
int work(int sta){
memset(dox, 0, sizeof dox);
memset(doy, 0, sizeof doy);
int res=0;
bool flag=0;
int last=0,left=r;
for(int i=1; i<=n; i++){
if(((sta>>(i-1)) & 1)==1){
dox[i]=1;
if(!flag){
flag=1;
res++;
last=i;
left--;
}
else{
if(last==i-1){
if(left==0){
left=r-1;
res++;
}
else{
left--;
}
last++;
}
else{
res++;
left=r-1;
last=i;
}
}
}
}
flag=0;
last=0;
left=c;
for(int i=1; i<=n; i++){
if(!dox[i]){
for(int j=1; j<=m; j++){
if(!doy[j] && !a[i][j]){
doy[j]=1;
}
}
}
}
res+=cal();
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
char ch=read();
if(ch=='.'){
a[i][j]=1;
}
else if(ch=='X'){
a[i][j]=0;
}
}
}
scanf("%d%d",&r,&c);
for(int i=0; i<(1<<n); i++){
ans=min(ans, work(i));
}
printf("%d\n",ans);
return 0;
}
T2
Description
鸡腿想到了一个很高(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取模就可以了哦!
Input
一行,输入两个正整数n,k。
Output
一行,输出一个整数表示答案。
Sample Input
输入1:
3 1
输入2:
100 2
Sample Output
输出1:
4
输出2:
321266186
Data Constraint
对于30%的数据0 <n ≤ 10, 0 <k ≤ 10;
对于100%的数据0 <n ≤ 1000, 0 <k ≤ 100。
Solution
令f[i][j][x]表示n=i,k=j时第x个质数有几个。
初值:f[i][0][x]=i分解质因数后第x个质数的个数。
转移:f[i][j][x]=(f[i-1][j][x]+f[i][j-1][x])%mod
1000以内的质数有168个,所以:
空间复杂度
O
(
168
×
N
K
)
O(168\times NK)
O(168×NK)
时间复杂度
O
(
168
×
N
K
)
O(168\times NK)
O(168×NK)
空间卡的比较紧,不要在f上开long long,ans上开即可。
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1010;
const int K = 110;
const int P = 170;
const int mod = 1000000009;
int n,k,pri[N],cntp;
long long ans=1;
bool vis[N];
int f[N][K][P];
void init(){
for(int i=2; i<=n; i++){
if(!vis[i]){
pri[++cntp]=i;
for(int j=1; j<=n/i; j++){
vis[i*j]=1;
}
}
}
}
int main(){
scanf("%d%d",&n,&k);
init();
for(int i=1; i<=n; i++){
int x=i;
for(int j=1; j<=cntp; j++){
while(x%pri[j]==0 && x>0){
f[i][0][j]++;
x/=pri[j];
}
}
}
for(int i=1; i<=n; i++){
for(int j=1; j<=k; j++){
for(int p=1; p<=cntp; p++){
f[i][j][p]=(f[i-1][j][p]+f[i][j-1][p])%mod;
}
}
}
for(int i=1; i<=cntp; i++){
ans=(ans*(long long)(f[n][k][i]+1))%mod;
}
printf("%lld\n",ans);
return 0;
}
T3
Description
Solution
奇怪的做法。我的代码代码实在很丑,简单实现即可。
咕咕咕。