USACO-Section 1.3 Combination Lock[...]

2017-05-30


以下这块属于个人牢骚*_*||:

目前临近期末,有若干的事情要做,尤其是对我这个编程菜鸟来说,,数据库课设的管理系统程序简直就像个去火星的任务-_-||此外还有其他科目的各种报告,系统设计……
最近三天是端午假,我过的很简单。每天就是刷USACO题,刷USACO题,刷USACO题。这样感觉很充实,虽然每天熬夜早起,却不感到疲惫。平时总是10点之前就手机关机,睡觉,6点闹钟,生活极其无聊~_~感觉最近几天真的很开心,可以说不太可能有比这样更让人开心的日子了:目标简单明确,只要理清思路,将其表达出来,结果毫不含糊,没有更复杂的标准和其他必须考虑的事情。以后大概难得有如此单纯的时光了……从容忘记生活。
^_^ carry on..Anyway.

 祝大家端午快乐~

题目大意:

输入的第一行为一个整数N (1 <= N <= 100),表示密码中每个数字的取值范围。其中,密码由三位整数构成。接下来的两行每行有三个整数,分别由空格隔开,表示两个标准密码。可行密码是三位密码数字每一位与两个标准密码任一一个的对应位相差都不大于2的密码。此外,密码是循环的,比如N=50时,1与50看成相邻的数字,等同于2和1的关系。

样例输入:

50
1 2 3
5 6 7

样例输出:

249

输出解析:
在这个样例中,可行密码有以下249个:

1,1,1  2,2,4  3,4,2  4,4,5  5,4,8  
6,5,6  7,5,9  3,50,2  50,1,4 
1,1,2  2,2,5  3,4,3  4,4,6  5,4,9  
6,5,7  7,6,5  3,50,3  50,1,5 
1,1,3  2,3,1  3,4,4  4,4,7  5,5,5  
6,5,8  7,6,6  3,50,4  50,2,1 
1,1,4  2,3,2  3,4,5  4,4,8  5,5,6  
6,5,9  7,6,7  3,50,5  50,2,2 
1,1,5  2,3,3  3,4,6  4,4,9  5,5,7  
6,6,5  7,6,8  49,1,1  50,2,3 
1,2,1  2,3,4  3,4,7  4,5,5  5,5,8  
6,6,6  7,6,9  49,1,2  50,2,4 
1,2,2  2,3,5  3,4,8  4,5,6  5,5,9  
6,6,7  7,7,5  49,1,3  50,2,5 
1,2,3  2,4,1  3,4,9  4,5,7  5,6,5  
6,6,8  7,7,6  49,1,4  50,3,1 
1,2,4  2,4,2  3,5,5  4,5,8  5,6,6  
6,6,9  7,7,7  49,1,5  50,3,2 
1,2,5  2,4,3  3,5,6  4,5,9  5,6,7  
6,7,5  7,7,8  49,2,1  50,3,3 
1,3,1  2,4,4  3,5,7  4,6,5  5,6,8  
6,7,6  7,7,9  49,2,2  50,3,4 
1,3,2  2,4,5  3,5,8  4,6,6  5,6,9  
6,7,7  7,8,5  49,2,3  50,3,5 
1,3,3  3,1,1  3,5,9  4,6,7  5,7,5  
6,7,8  7,8,6  49,2,4  50,4,1 
1,3,4  3,1,2  3,6,5  4,6,8  5,7,6  
6,7,9  7,8,7  49,2,5  50,4,2 
1,3,5  3,1,3  3,6,6  4,6,9  5,7,7  
6,8,5  7,8,8  49,3,1  50,4,3 
1,4,1  3,1,4  3,6,7  4,7,5  5,7,8  
6,8,6  7,8,9  49,3,2  50,4,4 
1,4,2  3,1,5  3,6,8  4,7,6  5,7,9  
6,8,7  1,50,1 49,3,3  50,4,5 
1,4,3  3,2,1  3,6,9  4,7,7  5,8,5  
6,8,8  1,50,2 49,3,4  49,50,1
1,4,4  3,2,2  3,7,5  4,7,8  5,8,6  
6,8,9  1,50,3 49,3,5  49,50,2
1,4,5  3,2,3  3,7,6  4,7,9  5,8,7  
7,4,5  1,50,4 49,4,1  49,50,3
2,1,1  3,2,4  3,7,7  4,8,5  5,8,8  
7,4,6  1,50,5 49,4,2  49,50,4
2,1,2  3,2,5  3,7,8  4,8,6  5,8,9  
7,4,7  2,50,1 49,4,3  49,50,5
2,1,3  3,3,1  3,7,9  4,8,7  6,4,5  
7,4,8  2,50,2 49,4,4  50,50,1
2,1,4  3,3,2  3,8,5  4,8,8  6,4,6  
7,4,9  2,50,3 49,4,5  50,50,2
2,1,5  3,3,3  3,8,6  4,8,9  6,4,7  
7,5,5  2,50,4 50,1,1  50,50,3
2,2,1  3,3,4  3,8,7  5,4,5  6,4,8  
7,5,6  2,50,5 50,1,2  50,50,4
2,2,2  3,3,5  3,8,8  5,4,6  6,4,9  
7,5,7  3,50,1 50,1,3  50,50,5
2,2,3  3,4,1  3,8,9  5,4,7  6,5,5  7,5,8

题解:

个人思路为:先求出所给的两个标准密码对应的6个数字,每个数字的可行范围(从值比它小2的数字到值比它大2的数字),再求出两个密码对应的三个位置的整数的可行范围的重叠值。最终的解为最初可行范围的数字决定的组合减去重叠范围的数字决定的组合。
要注意的是:(-_-||就知道每次样例里的输入总是比真实的测试数据友好)
N可以比5小,也就是每个数字的可行范围不一定是5。
!_!说真的,提交之前本人没有想到N竟然还能比3(密码位数)小,比如这个输入:
1
1 1 1
1 1 1
*_*||不过其实像这样的特殊情况很容易考虑到…

代码如下:

/*
ID: madara01
PROG: combo
LANG: C++
*/
#include <iostream>                  
#include <fstream>
#include <string>
#include <cmath>
#define cin fin
#define cout fout
#define MAX 10

using namespace std;

int n;
int master1,master2,master3;  //主人密码的三位
int maker1,maker2,maker3;     //制造者密码的三位
int allCodes[6][6];           //六个密码位决定的范围,0号存储范围中数字的数量
int result = 0;               //结果

void same()
{
    result = allCodes[0][0]*allCodes[1][0]*allCodes[2][0] + allCodes[3][0]*allCodes[4][0]*allCodes[5][0];
    int i,j,k;
    int m[3];          //两个给定密码中三位决定的范围重合的数字数目
    for(i = 0; i < 3; i++)  m[i] = 0;
    for(i = 0; i < 3; i++)
    {
        for(j = 1; j <= allCodes[i][0]; j++)
        {
            for(k = 1; k <= allCodes[i+3][0]; k++)
            {
                if(allCodes[i][j] == allCodes[i+3][k])
                {
                    m[i]++;
                }
            }
        }
    }
    result = result - m[0]*m[1]*m[2];
}

void decide()   //初始化allCodes
{
    int i,j;
    for(i = 0; i < 6; i++)
    {
        j = (allCodes[i][3] - 1 + n) % n;
        allCodes[i][1] = j == 0?n:j;
        j = (allCodes[i][3] - 2 + n) % n;
        allCodes[i][2] = j == 0?n:j;
        if(n == 3)
        {
            allCodes[i][0] = 3;
        }
        else if(n == 4)
        {
            j = (allCodes[i][3] + 1) % n;
            allCodes[i][4] = j == 0?n:j;
            allCodes[i][0] = 4;
        }
        else{
            j = (allCodes[i][3] + 1) % n;
            allCodes[i][4] = j == 0?n:j;
            j = (allCodes[i][3] + 2) % n;
            allCodes[i][5] = j == 0?n:j;
            allCodes[i][0] = 5;
        }
    }
}

int main()
{
    ofstream fout ("combo.out");
    ifstream fin ("combo.in");
    cin >> n;
    cin >> master1 >> master2 >> master3;
    cin >> maker1 >> maker2 >> maker3;
    if(n == 1)  result = 1;
    else if(n == 2)  result = 8;
    else{
        allCodes[0][3] = master1;
        allCodes[1][3] = master2;
        allCodes[2][3] = master3;
        allCodes[3][3] = maker1;
        allCodes[4][3] = maker2;
        allCodes[5][3] = maker3;
        decide();
        same();
    }
    cout << result << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值