SCOI 2009

BZOJ 1024 生日快乐 (DFS)

Description

windy的生日到了,为了庆祝生日,他的朋友们帮他买了一个边长分别为 X 和 Y 的矩形蛋糕。现在包括windy
,一共有 N 个人来分这块大蛋糕,要求每个人必须获得相同面积的蛋糕。windy主刀,每一切只能平行于一块蛋糕
的一边(任意一边),并且必须把这块蛋糕切成两块。这样,要切成 N 块蛋糕,windy必须切 N-1 次。为了使得
每块蛋糕看起来漂亮,我们要求 N块蛋糕的长边与短边的比值的最大值最小。你能帮助windy求出这个比值么?

Input

包含三个整数,X Y N。1 <= X,Y <= 10000 ; 1 <= N <= 10

Output

包含一个浮点数,保留6位小数。

Sample Input

5 5 5

Sample Output

1.800000

dfs搜索

/**************************************************************
    Problem: 1024
    User: wiiind
    Language: C++
    Result: Accepted
    Time:224 ms
    Memory:1288 kb
****************************************************************/
 
#include<cstdio>
#include<iostream>
using namespace std;
  
int x,y,n;
  
double DFS(double x,double y,int d){
    if(d == 1) return max(x,y)/min(x,y);
    double res=23333333.33;
    for(int i=1;i<d;i++) res=min(res,max(DFS(x,y*i/d,i),DFS(x,y*(d-i)/d,d-i)));
    for(int i=1;i<d;i++) res=min(res,max(DFS(x*i/d,y,i),DFS(x*(d-i)/d,y,d-i)));
    return res;
}
int main(){
    cin>>x>>y>>n;
    printf("%.6lf",DFS(x,y,n));
    return 0;
}


BZOJ 1025 游戏(线性筛+线性DP)

Description

windy学会了一种游戏。对于1到N这N个数字,都有唯一且不同的1到N的数字与之对应。最开始windy把数字按
顺序1,2,3,……,N写一排在纸上。然后再在这一排下面写上它们对应的数字。然后又在新的一排下面写上它们
对应的数字。如此反复,直到序列再次变为1,2,3,……,N。
如: 1 2 3 4 5 6 对应的关系为 1->2 2->3 3->1 4->5 5->4 6->6
windy的操作如下
1 2 3 4 5 6
2 3 1 5 4 6
3 1 2 4 5 6
1 2 3 5 4 6
2 3 1 4 5 6
3 1 2 5 4 6
1 2 3 4 5 6
这时,我们就有若干排1到N的排列,上例中有7排。现在windy想知道,对于所有可能的对应关系,有多少种可
能的排数。

Input

包含一个整数N,1 <= N <= 1000

Output

包含一个整数,可能的排数。

Sample Input

【输入样例一】
3
【输入样例二】
10

Sample Output

【输出样例一】
3
【输出样例二】
16

这道题有一定难度
显然dfs是不行的
思路:
考虑每个关系对答案的影响
可以模拟一下这个过程:
1.手动选取n种对应方式
2.将每一个数看做一个节点,将每一种对应方式看做一条有向边,例如:3可变成5,则从3节点连一条有向边到5节点
3.可以发现必定存在环,每个环的大小可以记录下来,则该种对应方式的集合的排数为这些环的大小的lcm
那么答案则变为有一个长度为n的数列
将其分为k个数列(不一定有序)
这k个数列的大小的lcm不同的方案数
一个很明显的DP(类似背包)
实现方式见代码

/**************************************************************
    Problem: 1025
    User: wiiind
    Language: C++
    Result: Accepted
    Time:40 ms
    Memory:9120 kb
****************************************************************/
 
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
int n;
const int maxn=1001;
bool v[maxn];
int pri[maxn];
int prinum;
long long f[maxn][maxn];
int main(){
    scanf ("%d",&n);
    prinum=0;
    for (register int i=2;i<=1000;++i){
        if (!v[i]) pri[++prinum]=i;
        for (int j=1;j<=prinum&&i*pri[j]<=1000;++j){
            v[i*pri[j]]=1;
            if (!(i%pri[j])) break ;
        }
    }
    f[0][0]=1;
    for (register int i=1;i<=prinum;++i){
        for (int j=0;j<=n;++j) f[i][j]=f[i-1][j];
        for (int j=pri[i];j<=n;j*=pri[i]) for (int k=0;k<=n-j;++k) f[i][k+j]+=f[i-1][k];
    }
    long long ans=0;
    for (register int i=0;i<=n;++i) ans+=f[prinum][i];
    printf ("%lld",ans);
    return 0;
}

BZOJ 1026 windy数(计数DP)

Description

windy定义了一种windy数。不含前导零且相邻两个数字之差至少为2的正整数被称为windy数。 windy想知道,
在A和B之间,包括A和B,总共有多少个windy数?

Input

包含两个整数,A B。

Output

一个整数

Sample Input

【输入样例一】
1 10
【输入样例二】
25 50

Sample Output

【输出样例一】
9
【输出样例二】
20

HINT

【数据规模和约定】
100%的数据,满足 1 <= A <= B <= 2000000000 。

一道经典的计数DP
注意压界问题

/**************************************************************
    Problem: 1026
    User: wiiind
    Language: C++
    Result: Accepted
    Time:40 ms
    Memory:824 kb
****************************************************************/
 
#include<cstdio>
#include<memory.h>
#include<algorithm>
 
int f[20][20];
 
void init()
{
    memset(f,0,sizeof(f));
    for(int i=0;i<10;i++) 
        f[1][i]=1;
    for(int i=2;i<=10;i++)
        for(int j=0;j<10;j++)
            for(int k=0;k<10;k++)
                if(abs(j-k)>=2)
                    f[i][j]+=f[i-1][k];
}
int solve(int x)
{
    int ans=0,len=0;
    int b[20];
    while (x>0)
    {
        b[++len]=x%10;
        x/=10;
    }
    for (int i=1;i<len;i++)
        for (int j=1;j<10;j++)
            ans+=f[i][j];
    for (int i=1;i<b[len];i++) 
        ans+=f[len][i];
    for (int i=len-1;i>0;i--)
    {
        for (int j=0;j<b[i];j++)
            if (abs(j-b[i+1])>=2) 
                ans+=f[i][j];
        if (abs(b[i]-b[i+1])<2) 
            break;
    }
    return ans;
}
 
int main()
{
    int x,y;
    init();
    scanf("%d%d",&x,&y);
    printf("%d",solve(y+1)-solve(x));
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值