UVA846 Steps

一個人沿著一數線前進。他每次走的長度(整數)必須是正的,而且比上一步走的長度多1,一樣,或少1。另外請注意:第一步及最後一步的長度一定是1.

請問這個人若要從x走到y,最少需要走幾步。

舉例說明:若x=45, y=50,那麼每步走的長度可以是:1,2,1,1,所以最少需要4步。

Input

輸入的第一列有一個正整數代表以下有幾組測試資料。每組測試資料一列,含有2個整數x,y(0 <= x <= y < 231)。

Output

每組測試資料輸出一列,最少需要走幾步才能從x走到y。

Sample Input

3
45 48
45 49
45 50

Sample Output

3
3
4

找出步數與距離的關係即可得解。

  • 0步最多能抵達的距離是0
  • 1步最多能抵達的距離是1(1)
  • 2步最多能抵達的距離是2(1 1)
  • 3步最多能抵達的距離是4(1 2 1)
  • 4步最多能抵達的距離是6(1 2 2 1)
  • 5步最多能抵達的距離是9(1 2 3 2 1)
  • 6步最多能抵達的距離是12(1 2 3 3 2 1)
  • ……以此類推

 

题意:在给出的两个数A,B,找出最少需要几步可以从A到B,规则:第一步和最后一步必须是1,还有中途只可以比前一数大一,等于,或小一。。

第一种方法:从A,B开始依次加,然后距离减去步长,直到 dis<0 ,我们可以肯定的是,小于零的这部分C,一定小于当前的步长N,所以我们一定能在之前的步长中找到(N-C),也就可以填满这一部分。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
 
int n;
 
int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int dis = b - a ;
        bool flag = false ;
        int count = 0 ;
        int step = 1 ;
        while (dis > 0 )
        {
            dis -= step;
            count++;
            if (flag)
                step++;
            flag = !flag;
        }
        printf("%d\n",count);
    }
    return 0;

第二种方法:1+2+…..+(n-1)+n+(n-1)+….2+1 =n^2,这是我们在达到和为n^2在满足题意的情况下能确定的最少步数,设想我们如果 dis==n^2 ,那结果就显而易见了,当dis > n^2的时候,首先我们先确定最大的n满足 n^2 <= dis ,然后我们只要再找dis-n^2的数就可以,如果dis-n^2<=n,那只要再找一个,如果>n,但我们发现这个数一定<(n+1)^2-n^2

,那这个数一定可以化为数列中的两个数。。。

/*
Author:ZCC;
Solve:
// 所走步数对应的序列如果左右对称,那么所走的步数应该是最少的。因为最先一步和最后一步长度均必须是
// 1,又由于每一步的长度必须是非负整数,且要么比上一步步长恰好大 1,要么相等,要么小 1,则左右对
// 称的序列能在最少步数得到最大距离。如果采取左右对称的走法,设两点距离为 distance,n = sqrt
// (distance),则由于最大步数为 n 步时能达到的距离是 1 + 2 + 3 + ... + (n - 1) + n +
// (n - 1) + ... + 3 + 2 + 1 = n^2。比较两点距离 distance 与 n^2,若相等,表明只需走
// 2 * (n - 1) + 1 = 2 * n - 1 步,否则若剩余距离 distance - n^2 在 1 - (n + 1),
// 只需插入一步即可,若 distance - n^2 大于 (n + 1),则需多插入两步即可。
*/

#include <iostream>
#include <cstdio>
#include <cmath>
using namespace std;
 
int main()
{
    int t ;
    scanf("%d",&t);
    while (t--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        int dis = b - a ;
        if (dis <= 3)
            printf("%d\n",dis);
        else
        {
            
            int n = sqrt(dis);
            if ( n * n == dis)
                printf("%d\n",2*n-1);
            else if ((dis-n*n)<=n)
                printf("%d\n",2*n);
            else  printf("%d\n",2*n+1);
        }
    }
    return 0;
}

列出几项,找到规律:

1: 1
2 1 1
3 1 1 1
4: 1 2 1
5 1 2 1 1
6 1 2 2 1
7 1 2 2 1 1
8 1 2 2 2 1
9: 1 2 3 2 1
10 1 2 3 2 1 1
11 1 2 3 2 2 1
12 1 2 3 3 2 1
13 1 2 3 3 2 1 1
14 1 2 3 3 2 2 1
15 1 2 3 3 3 2 1
16: 1 2 3 4 3 2 1

可以得出 n * n : 2 * n – 1

综合得出:

n * n: 1……n……1 minstep: 2 * n – 1.

n * ( n + 1 ) 1…..n,n…….1 minstep: 2 * n

(n + 1) * ( n + 1 ) :1……n+1………1 minstep: 2 * n + 1

代码:

#include <stdio.h>
#include <math.h>
 
int main()
{
    int ncase;
    scanf("%d", &ncase);
    while (ncase--)
    {
        int x, y;
        scanf("%d%d", &x, &y);
        x = y - x;
        if (x == 0)//debug
            printf("0\n");
        else
        {
            y = (int)sqrt(x);
            if (x == y * y)
            {
                printf("%d\n", 2 * y - 1);
            }
            else if (x <= y * (y + 1))
            {
                printf("%d\n", 2 * y);
            }
            else
            {
                printf("%d\n", 2 * y + 1);
            }
        }
    }
    return 0;
}

 

UVa 10167 Birthday Cake

题目:给你2N个点。输出一条直线Ax+By=0,使得在直线两边均有n个点,点不在直线上。

分析:搜索、枚举。因为区间是A,B区间是[-500,500],直接枚举即可;

判断在直线的方向,直接带入方程求解。

说明:暴力(⊙_⊙)!

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstdio>
 
using namespace std;
 
typedef struct pnode
{
    int x,y;
}point;
point P[100];
 
int main()
{
    int n;
    while ( ~scanf("%d",&n) && n ) {
        for ( int i = 0 ; i < 2*n ; ++ i )
            scanf("%d%d",&P[i].x,&P[i].y);
        
        int flag = 1;
        for ( int A = -500 ; flag && A <= 500 ; ++ A )
        for ( int B = -500 ; flag && B <= 500 ; ++ B ) {
            int l = 0,r = 0;
            for ( int i = 0 ; i < 2*n ; ++ i ) {
                l += (A*P[i].x+B*P[i].y>0);
                r += (A*P[i].x+B*P[i].y<0);
            }
            if ( l == n && r == n ) {
                printf("%d %d\n",A,B);
                flag = 0;
            }
        }
    }
    return 0;
}

 

UVa 10929 You can say 11

你的任務是,給你一個正整數 N,判定它是否是 11 的倍數。

Input

每列資料有一個正整數N,N 最大可能到 1000 位數。

若 N = 0 代表輸入結束。

Output

對每個輸入的數,輸出是否為 11 的倍數。輸出格式請參考 Sample Output。

 

方法1:直接从个位数开始mod 11计算。

 /*0.026s*/  
  
#include<cstdio>  
#include<cstring>  
  
char s[1005];  
  
int main(void)  
{  
    int remainder;  
    while (gets(s), strcmp(s, "0"))  
    {  
        remainder = 0;  
        for (int i = 0; s[i]; i++)  
            remainder = (remainder * 10 + (s[i] & 15)) % 11;  
        if (remainder) printf("%s is not a multiple of 11.\n", s);  
        else printf("%s is a multiple of 11.\n", s);  
    }  
    return 0;  
}

备注:&15按位与的意思 每位同时为1才为1,否则为0

 

方法2:若一个整数的奇位数字之和与偶位数字之和的差能被11整除,则这个数能被11整除。

证明:比如num = 10000a4+1000a3+100a2+10a1+a0=(a4+a2+a0-a3-a1)+(9999a4+99a2+1001a3+11a1)

因为11 | 99,所以11 | (9900+99)

因为11 | 1111,所以11 | (1111-110)

所以…

 /*0.025s*/  
  
#include<cstdio>  
#include<cstring>  
  
char s[1005];  
  
int main(void)  
{  
    int l, i, sum;  
    while (gets(s), strcmp(s, "0"))  
    {  
        l = strlen(s), sum = 0;  
        for (i = 0; i < l; i += 2) sum += s[i] & 15;  
        for (i = 1; i < l; i += 2) sum -= s[i] & 15;  
        if (sum % 11) printf("%s is not a multiple of 11.\n", s);  
        else printf("%s is a multiple of 11.\n", s);  
    }  
    return 0;  
}

 

UVA 10878 Decode the tape

【解析】:

输入从上往下看,可以看成题目所说的一段磁带。
题目给的信息很少,因此大部分信息要从输入输出得到。
(相当于给你一段明文跟密码,然后你破解其中的加密规则)

首先我们发现,磁带一共有43行,跟密码的字符个数一样(换行包括在内)。
可以猜测是否磁带的一行,代表一个字符。
然后我们可以发现,密码中相同的字符,在磁带里面的对应行,也是相同的。
更加坚定我们的猜测。

然后我们观察磁带里每行的结构。
其整体的格式一样,只有 “o” 的位置和数量有不同。
而且 “o” 只会在固定的7个位置出现。
则 7 个位置,一共可以表示出 2^7=128 种字符。
联系字符的整型特征(ASCII码),
可以猜测,磁带的每行表示着一个二进制数,这个二进制数的数值正好是对应字符的ASCII码。

看一下空格(ASCII码为32)的对应行 “ o . ”,
把行中的空格看作0,“o” 看作1,则可以得到二进制数0100000,正好是32。
破译完毕。

/*********************************
*   日期:2013-5-3
*   作者:SJF0115
*   题号: 10878 - Decode the tape
*   来源:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=20&page=show_problem&problem=1819
*   结果:AC
*   来源:UVA
*   总结:
**********************************/
#include <stdio.h>
#include <string.h>
 
int c[] = { 0, 0, 64, 32, 16, 8, 0, 4, 2, 1, 0};
 
int main() {
    char str[15];
    int value,i;
    //freopen("C:\\Users\\XIAOSI\\Desktop\\acm.txt","r",stdin);   
    gets(str);
    while(gets(str) && str[0] != '_'){
        value = 0;
        int len = strlen(str);
        for(i = 2;i < len;i++){
            if(str[i] == 'o'){
                value += c[i];
            }
        }
        printf("%c",value);
    }
}

 

[演算法笔记]小画家到墨水

void flood(int x, int y, int new_color, int old_color)
{
    if (x>=0 && x<10 && y>=0 && y<10)
        if (image[x][y] == old_color)
        {
            image[x][y] = new_color;
 
            // 寫成一個迴圈
            for (int i=0; i<4; i++)
            {
                static int dx[4] = {1, -1, 0, 0};
                static int dy[4] = {0, 0, 1, -1};
                flood(x + dx[i], y + dy[i], new_color, old_color);
            }
        }
}

 

[演算法笔记]尋找總和為 10 的區間

void find_interval(int array[], int n, int num)
{
    int sum = 0;
    for (int i=0, j=0; j<=n; )  // 枚舉區間[i, j)
    {
        if (sum > num)
            sum -= array[i++];
        else
            sum += array[j++];
 
        if (sum == num)
            cout << '[' << i << ',' << j-1 << ']';
    }
}

 

[演算法笔记]英文單字從單數變複數

void plural(string s)
{
    int n = s.length();
    if (s.back() == 'y')
        cout << s.substr(0, n-1) << "ies";
    else if (s.back() == 's' || s.back() == 'x')
        cout << s << "es";
    else if (s.substr(n-2) == "sh" || s.substr(n-2) == "ch")
        cout << s << "es";
    else if (s.substr(n-3) == "man")
        cout << s.substr(0, n-3) << "men";
    else
        cout << s << 's';
}

 

[演算法笔记]尋找陣列之中的特定數字,陣列已經由小到大排序

void find_number()
{
    int array[15] =
    {
        2, 3, 5, 7, 11,
        13, 17, 19, 23, 29,
        31, 37, 41, 43, 47
    };
 
    int left = 0, right = 15-1;
    while (left <= right)
    {
        int mid = (left + right) / 2;
        if (array[mid] < 29)
            left = mid + 1;     // 繼續搜尋剩下的右半段
        else if (array[mid] > 29)
            right = mid - 1;    // 繼續搜尋剩下的左半段
        else if (array[mid] == 29)
        {
            // 找到了其中一個數字
            cout << mid << ':' << array[mid];
            return;
        }
    }
 
    cout << "找不到29";
}

 

[演算法笔记]字串搜尋

void string_searching()
{
    char text[14] = "It's a pencil.";
    char pattern[6] = "a pen";
 
    // 仔細估量枚舉範圍
    for (int i=0; i<14-6+1; i++)
    {
        bool find = true;
        for (int j=0; j<5; j++)
            if (text[i+j] != pattern[j])
            {
                find = false;
                break;
            }
 
        if (find)
            cout << "短字串出現在第" << i << "個字元";
    }
}