一、复赛经历(题解)
第一题
pow
题目描述
小文同学刚刚接触了信息学竞赛,有一天她遇到了这样一个题:给定正整数a 和b,求a b 的值是多少。
a b 即b个a 相乘的值,例如 23即为3 个 2 相乘,结果为2 × 2 × 2 = 8。
“简单!”小文心想,同时很快就写出了一份程序,可是测试时却出现了错误。
小文很快意识到,她的程序里的变量都是 int 类型的。在大多数机器上, int 类型能表示的最大数为231 -1 ,因此只要计算结果超过这个数,她的程序就会出现错误。
由于小文刚刚学会编程,她担心使用 int 计算会出现问题。因此她希望你在 ab的值超过 109 时,输出一个 -1 进行警示,否则就输出正确的ab的值。
然而小文还是不知道怎么实现这份程序,因此她想请你帮忙。
输入描述
从文件 pow.in 中读入数据。
输入共一行,两个正整数a,b。
输出描述
输出到文件 pow.out 中。
输出共一行,如果ab 的值不超过 109 ,则输出ab 的值,否则输出 -1 。
样例1
输入 复制
10 9
输出
1000000000
样例2
输入 复制
23333 66666
输出
-1
提示
对于10%的数据,保证b = 1。
对于30%的数据,保证b ≤ 2。
对于60%的数据,保证b ≤ 30 , a b ≤1018。
对于100%的数据,保证1 ≤ a, b ≤ 109。
本题需要使用文件输入输出,而非标准输入输出。
freopen("pow.in","r",stdin);
freopen("pow.out","w",stdout);
解析
这是一道水题,但也有一个bug需要注意,就是当输入为1 时,如果不特判,循环就会真的执行次,很明显,这样肯定会超时,只要加一个特判就好啦(经验算,当输入为2 时循环只执行30次不到,log的复杂度)。
考场100分代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
freopen("pow.in","r",stdin);
freopen("pow.out","w",stdout);
ll a,b; scanf("%lld%lld",&a,&b);
ll ans=1;
if(a==1){
printf("1");
return 0;
}
for(ll i=1; i<=b; i++){
ans*=a;
if(ans>1e9){
printf("-1");
return 0;
}
}
printf("%lld",ans);
return 0;
}
第二题
decode
题目描述
给定一个正整数 k,有k 次询问,每次给定三个正整数ni , ei , di ,求两个正整数 pi ,qi ,使ni = pi ×qi 、ei ×di = (pi − 1) (qi − 1) + 1
输入描述
从文件 decode.in 中读入数据。
第一行一个正整数 k,表示有 k 次询问
接下来 k 行,第 i 行三个正整数ni , di , ei ,
输出描述
输出到文件 decode.out 中。
输出 k 行,每行两个正整数pi ,qi 表示答案。
为使输出统一,你应当保证pi ≤ qi
如果无解,请输出 NO .
样例1
输入 复制
10 770 77 5 633 1 211 545 1 499 683 3 227 858 3 257 723 37 13 572 26 11 867 17 17 829 3 263 528 4 109
输出
2 385 NO NO NO 11 78 3 241 2 286 NO NO 6 88
提示
【样例 2】
见选手目录下的 decode/decode2.in 与 decode/decode2.ans。
【样例 3】
见选手目录下的 decode/decode3.in 与 decode/decode3.ans。
【样例 4】
见选手目录下的 decode/decode4.in 与 decode/decode4.ans。
【数据范围】
以下记 m=n - e × d + 2 。
保证对于100%的数据,1 ≤ k ≤ 105 ,对于任意的 1 ≤ i ≤ k , 1 ≤ ni ≤ 1018 ,1 ≤ ei ×di ≤ 1018 , 1 ≤ m ≤ 109
测试点编号 | k\lek≤ | n\len≤ | m\lem≤ | 特殊性质 |
---|---|---|---|---|
11 | 10^3103 | 10^3103 | 10^3103 | 保证有解 |
22 | 10^3103 | 10^3103 | 10^3103 | 无 |
33 | 10^3103 | 10^9109 | 6\times10^46×104 | 保证有解 |
44 | 10^3103 | 10^9109 | 6\times10^46×104 | 无 |
55 | 10^3103 | 10^9109 | 10^9109 | 保证有解 |
66 | 10^3103 | 10^9109 | 10^9109 | 无 |
77 | 10^5105 | 10^181018 | 10^9109 | 保证若有解则p=q |
88 | 10^5105 | 10^181018 | 10^9109 | 保证有解 |
99 | 10^5105 | 10^181018 | 10^9109 | 无 |
1010 | 10^5105 | 10^181018 | 10^9109 | 无 |
本题需要使用文件输入输出,而非标准输入输出。
freopen("decode.in","r",stdin);
freopen("decode.out","w",stdout);
解析
考试前两天刚学的一元二次方程,还不太熟练,就用了二分答案,整道题就变得很烦,还出了个bug,数据卡精度被扣了10分。
这里发一下线性的一元二次方程求根公式法吧(100分)(90分的二分代码找不到了):
(P.S.:
求根公式:对于一元二次方程)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
ll k; scanf("%lld",&k);
while(k--){
ll n,d,e; scanf("%lld%lld%lld",&n,&d,&e);
ll m=n-e*d+2;
ll delta=m*m-4*n;
if(delta<0){
printf("NO\n");
continue;
}
ll s=sqrt(delta);
if(s*s==delta && (m+s)%2==0)
printf("%lld %lld\n",(m-s)/2,(m+s)/2);
else printf("NO\n");
}
return 0;
}