【统计数字】【SCOI2009】windy数

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

【输入格式】
输入文件windy.in包含两个整数,A B。

【输出格式】
输出文件windy.out包含一个整数。

【输入样例一】
1 10

【输出样例一】
9

【输入样例二】
25 50

【输出样例二】
20

【数据规模和约定】
20%的数据,满足 1 <= A <= B <= 1000000 。
100%的数据,满足 1 <= A <= B <= 2000000000 。
此题为数字统计型问题。

首先一个动态规划:
用f[i][j]表示最高位为j(包括前导0)的(i+1)位数中所有windy数的总数。
f[i][j] = sigma(|k-j| >= 2) {f[i - 1][k]}。
                  ___________________
设要求的区间为[0, a(n-1)a(n-2)...a1a0)。
那么,分为以下几步求解:
           _____________
 1) 求出[0,a(n-1)00...00)中windy数的个数即
    sigma(i = 0; i < n-1; ++i) sigma(j = 1; j < 10; ++j) {f[i][j]}
         _____________  ___________________
 2) 求出[a(n-1)00...00, a(n-1)a(n-2)00...00)中windy的个数即
            _____________
        [0, a(n-2)00...00)且满足10^(n-2)位上的数与较高一位之差的绝对值大于等于2。
     可先将当前最高位去掉,并将n自减1,然后重复步骤2),直到该数变成0为止。

提交情况:共提交5次。
第一次0分,WrongAnswer * 10。
第二次20分,WrongAnswer * 8。
第三次40分,WrongAnswer * 6。
第四次80分,WrongAnswer * 2。

第四次100分。

ACCode(C风格):

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

int f[20][20];
int A, B;
char a[20], b[20];

int calc(char *s)
{
    int len = strlen(s), ans = 0;
	std::reverse(s, s + len);
    for (int i = 0; i < len; ++i)
        s[i] -= '0';
    for (int i = 0; i < len - 1; ++i)
        for (int j = 1; j < 10; ++j)
            ans += f[i][j];
    for (int j = 1; j < s[len - 1]; ++j)
        ans += f[len - 1][j];
    for (int i = len - 2; i > -1; --i)
    {
        for (int j = 0; j < s[i]; ++j)
            if (abs(j - s[i + 1]) > 1)
                ans += f[i][j];
        if (abs(s[i] - s[i + 1]) < 2)
	//若当前数位和较高一位数字相差大于1则可直接退出。
        {
            std::reverse(s, s + len);
            for (int i = 0; i < len; ++i)
                s[i] += '0';
            return ans;
        } //
    }
    std::reverse(s, s + len);
    for (int i = 0; i < len; ++i)
        s[i] += '0';
    return ans;
}

int main()
{
    freopen("windy.in", "r", stdin);
    freopen("windy.out", "w", stdout);
    scanf("%d%d", &A, &B);
    sprintf(a, "%d", A);
    sprintf(b, "%d", ++B);
    for (int j = 0; j < 10; ++j) f[0][j] = 1;
    for (int i = 1; i <= strlen(b); ++i)
        for (int j = 0; j < 10; ++j)
            for (int k = 0; k < 10; ++k)
                if (abs(j - k) > 1)
                    f[i][j] += f[i - 1][k];
    printf("%d\n", calc(b) - calc(a));
    return 0;
}
ACCode(C++风格):
#include <fstream>
#include <sstream>
#include <cstring>
#include <algorithm>

std::stringstream ss;
int f[20][20], A, B;
std::string a, b;

int calc(std::string s)
{
    if (s == "0") return 0;
    int sz = s.size(), ans = 0;
    reverse(s.begin(), s.end());
    for (int i = 0; i < sz - 1; ++i)
        for (int j = 1; j < 10; ++j)
            ans += f[i][j];
    for (int j = '1'; j < s[sz - 1]; ++j)
        ans += f[sz - 1][j - '0']; //
    for (int i = sz - 2; i > -1; --i)
    {
        for (int j = '0'; j < s[i]; ++j)
            if (abs(j - s[i + 1]) > 1)
                ans += f[i][j - '0'];
        if (abs(s[i] - s[i + 1]) < 2)
            return ans;
    }
    return ans;
}

int main()
{
    std::ifstream cin("windy.in");
    cin >> A >> B;
    cin.close();
    ss << A;
    ss >> a;
    ss.clear();
    ss << ++B;
    ss >> b;
    ss.clear();
    for (int j = 0; j < 10; ++j) f[0][j] = 1;
    for (int i = 1; i <= b.size(); ++i)
        for (int j = 0; j < 10; ++j)
            for (int k = 0; k < 10; ++k)
                if (abs(j - k) > 1)
                    f[i][j] += f[i - 1][k];
    std::ofstream cout("windy.out");
    cout << calc(b) - calc(a) << std::endl;
    cout.close();
	return 0;
}

中描述了一个幼儿园里分配糖果的问题,每个小朋友都有自己的要求。问题的输入包括两个整NN和KK,表示幼儿园里的小朋友量和要满足的要求量。接下来的KK行表示小朋友们的要求,每行有三个字,XX,AA,BB。如果X=1,表示第AA个小朋友分到的糖果必须和第BB个小朋友分到的糖果一样多;如果X=2,表示第AA个小朋友分到的糖果必须少于第BB个小朋友分到的糖果;如果X=3,表示第AA个小朋友分到的糖果必须不少于第BB个小朋友分到的糖果;如果X=4,表示第AA个小朋友分到的糖果必须多于第BB个小朋友分到的糖果;如果X=5,表示第AA个小朋友分到的糖果必须不多于第BB个小朋友分到的糖果。这个问题可以被看作是一个差分约束系统的问题。 具体地说,可以使用差分约束系统来解决这个问题。差分约束系统是一种通过给变量之间的关系添加约束来求解最优解的方法。对于这个问题,我们需要根据小朋友们的要求建立约束条件,并通过解决这个约束系统来得出最小的糖果量。 在问题的输入中,X的取值范围为1到5,分别对应不同的关系约束。根据这些约束,我们可以构建一个差分约束图。图中的节点表示小朋友,边表示糖果量的关系。根据不同的X值,我们可以添加相应的边和权重。然后,我们可以使用SPFA算法(Shortest Path Faster Algorithm)来求解这个差分约束系统,找到满足所有约束的最小糖果量。 需要注意的是,在读取输入时需要判断X和Y是否合法,即是否满足X≠Y。如果X=Y,则直接输出-1,因为这种情况下无法满足约束条件。 综上所述,为了满足每个小朋友的要求,并且满足所有的约束条件,我们可以使用差分约束系统和SPFA算法来求解这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【差分约束系统】【SCOI2011】糖果 candy](https://blog.csdn.net/jiangzh7/article/details/8872699)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [P3275 [SCOI2011]糖果(差分约束板子)](https://blog.csdn.net/qq_40619297/article/details/88678605)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值