日常小收获

21 篇文章 1 订阅

Winter Holiday Training Competition 2019, Post-competition Reflections 

1、

Cutting Out

CodeForces - 1077D

这是第四场的训练赛中的一个题目,这个题就是利用二分找最优解,最后输出,挺常规的题目,当时在第40个样例T了4次,当时真的不甘心,现在看来只能怪自己的思维不够严谨。
一方面:

在二分的时候把 l 设置为0,那么假设只有右边的1成立,那么最后就会剩余0与1,在逼近最优解的时候,0 + 1 )/ 2 == 0 这时候逼近的是0到没关系,因为xx变量已经把最优解1保留着,0将会不成立,但是再判断时 0 这个解却会在分母上,导致程序崩溃。
如果确定最优解不是0,就尽量l设置为1,二分写法我现在也改变了原来的写作习惯,改成了如下所示:

int l = 1, r = n, xx = 1;
while(l <= r)
{
    int mid = (l + r) >> 1;
    if(f(mid)) l = mid + 1, xx = mid;  //x保留最优解
    else r = mid - 1;
}

另一方面:在最后输出的时候,没考虑好循环截止条件:

for(int i = k, j = 1; i > 0; j++)
    {
        int temp = a[j].time / xx;
        for(int p = 1; p <= temp && i > 0; p++, i--)
             printf("%d%c", a[j].val, i == 0 && p == temp ? '\n' : ' ');

    }

这里当时 i 只是控制  i  != 0 的时候,i < 0 的时候更不行,而且会出现 i < 0 的情况。
比如: 5  2    3 3 3 2 1 这一组样例就会让我Wa,因为这里确定的最优解是1,但是temp算出来是3 最后应输出2个值,但是由于我没有管i小于0的时候,于是呢,就凉凉了...      

2、关于精度问题

Pythagorean Theorem II

CodeForces - 304A

这个题其实就是遍历一下,判断三条边是否可以构成直角三角形,求出来 a^2 + b^2  怎么判断c是不是整数呢?
这里比较简单的就是:
 

double c = sqrt(a * a + b * b);
int t = c;
if((int)c * (int)c == t) puts("c是整数")

这样处理判断比较方便,一开始判断的麻烦了,导致因为精度问题WA了一发,下不为例了。

3、string转化为小写字母

#include <iostream>
#include <algorithm>
using namespace std;
string s;
int main() {
    cout<<"请输入一个含大写的字符串:";
    string str;
    cin>>str;
    ///转小写
    transform(str.begin(),str.end(),str.begin(),::tolower);
    cout<<"转化为小写后为:"<<str<<endl;
    transform(str.begin(),str.end(),str.begin(),::toupper);
    cout<<"转化为大写后为:"<<str<<endl;
    return 0;
}

4、reverse

vector:

vector<int> v={1,2,3,4,5};
reverse(v.begin(),v.end());//v的值为5,4,3,2,1

整型数组也是可以的,用法同上;

string:

string str="C++REVERSE";
reverse(str.begin(),str.end());//str结果为ESREVER++C

5、X^Y

给你两个数 l , r (0 <= l, r <= 1e15)让你求解 l ^ (l + 1) ^ (l + 2) ^ ·····^ (r - 2) ^ (r - 1) ^ r 的结果。

只需注意到一点即可: (2 * n) ^ (2 * n + 1) = 1  一个偶数相邻一个奇数,由于奇数只在它前面偶数的二进制的第一位多一个1,所以亦或以后等于1,再利用 a^a = 0的特点,根据1的个数的奇偶性来最后结果。

6、取上|下整

取上整函数:ceil(double);
取下整函数:floor(double);
头文件:#include<cmath>或#include<math.h>

7、输入输出

scanf("%1d", &n);
printf("%02d\n", n);
/***结果***/
56
05

scanf("%1d", &n);
printf("%2d\n", n);

/***结果***/
56
 5

8、范围问题 ***

The Super Powers

UVA - 11752

输出在范围 2^64 - 1范围内的,可以被拆成 至少两种数的n次方形式的数,例如:16 = 2^4 = 4 ^ 2 底数可以为2也可以为4.

所以一个数的指数只要是合数就可以,因为 (n^a)^b == (n^b)^a  能拆成像a * b 这样的数的应是合数。

所以先打表求1 - 64范围内的合数作为指数,又因为范围太大!!!  unsigned long long 的上限值,所以直接算出来一个数然后与 2^64 - 1进行比较是否小于它不现实,直接爆 unsigned long long 了,所以可以利用数学的思维。
如果求出 i ^ k < 2 ^ 64 的k的取值范围不就好了嘛,超过k的直接不求了,因为求了也就超了 2^64了
      i^k < 2 ^64
=>  log(i^k) < log(2^64)
=>  k * log(i) < 64 * log(2)
=>  k < (64 * log(2)) / log(i)
所以终止求取i^k,的条件由 i^k < 2^64 - 1  转换为==》 k < (64 * log(2)) / log(i) 。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cmath>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
#define MAXN 64
#define INF 0x3f3f3f3f
using namespace std;
typedef unsigned long long ull;
int prime[64 + 1];
void getprime()  //对合数打表
{
    for(int i = 2; i <= 64; i++){
        if(prime[i]) {prime[++prime[0]] = i; continue;}
        for(int j = i * 2; j <= 64; j += i){
            prime[j] = 1;
        }
    }
}
ull power(ull a, ull b)
{
    ull base = a, ans = 1;
    while(b)
    {
        if(b & 1){
            ans *= base;
        }
        base *= base;
        b >>= 1;
    }
    return ans;
}
int main()
{
    getprime();
    set<ull> set_;
    ull n = 1 << 16;
    set_.insert(1);
    for(ull i = 2; i < n; i++)
    {
        double t = 64 * log(2) / log(i);
        for(int j = 1; j <= prime[0] && prime[j] * 1.0 <= t; j++){
            set_.insert(power(i, prime[j]));
        }
    }
    set<ull> :: iterator iter = set_.begin();
    while(iter != set_.end())
    {
        if(*iter > 0) cout<<*iter<<'\n';
        iter++;
    }

}

9、枚举

枚举答案时,一般固定一个,另一个用二分枚举,或者求出验证,二分!二分!二分!

10、数学运算符号

exp(n) = e^n
log(n) = 以e为底n的对数
log10(n) = 以10为底n的对数
log(n)/log(m) = 以m为底n的对数
PI = acos(-1)
eps = 10^-6

11、STL   next_permutation()  与  prev_permutation()  

头文件:#include<algorithm>

next_permutation()函数的返回类型是bool类型.

即:如果有一个更高的排列,它重新排列元素,并返回true;如果这是不可能的(因为它已经在最大可能的排列),它按升序排列重新元素,并返回false

#include<cstdio>
#include<algorithm>
using namespace std;
int arr[4];
int main()
{
    arr[1] = 1, arr[2] = 2, arr[3] = 3;
    do{
        printf("%d %d %d\n", arr[1], arr[2], arr[3]);
    }while(next_permutation(arr + 1, arr + 1 + 3  ));
}

#include<cstdio>
#include<algorithm>
using namespace std;
int arr[4];
int main()
{
    arr[1] = 3, arr[2] = 2, arr[3] = 1;
    do{
        printf("%d %d %d\n", arr[1], arr[2], arr[3]);
    }while(prev_permutation(arr + 1, arr + 1 + 3  ));
}

例题:https://www.luogu.org/problemnew/show/P1088

12、int16  int32  int64:

Int16  相当于 short  占2个字节   -32768 ~ 32767

Int32  相当于 int      占4个字节   -2147483648 ~ 2147483647

Int64  相当于 long   占8个字节   -9223372036854775808 ~ 9223372036854775807

13、进制转换:

1 - A            26 - Z              27 - AA                 28 - AZ  

void _10_26(int n)
{
    stack<int> st;
    while(n)
    {
        st.push((n - 1) % 26);
        n = (n - 1) / 26;
    }
    while(!st.empty())
    {
        printf("%c", st.top() + 'A' );
        st.pop();
    }
}

14、格式输入方式:

char str[MAXN]; scanf("%s", &str);
int a, b;
if(sscanf(str, "R%dC%d", &a, &b) == 2)
{

}

else{}

15、字符串剪切

if(str[0] == '+') set_.insert(str.substr(1, str.length() - 1));
if(str[0] == '-') set_.erase(str.substr(1, str.length() - 1));
//str.substr(起点,长度)


16、string字符串反转

 

 

 

持续更新....

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值