找出最小的 n ,使对于给定的 S(0<S≤105) 使
首先知 n 的必要条件为 ∑i=1ni≥S 即 n×(n+1)2≥S ,设 Sn=n×(n+1)2 ,将 Sn 中的若干个 ki 从 1 改为 −1 后,发现 Si1,⋯,ik=Sn−2×∑i ,可见任意的 i 的取法使 Sn 减去某个偶数,再进一步,可知 Si=Sn−{0,2,⋯,2Sn} ,若使 S=Si 则 Sn−Smod2=0 .
所以当我们从 n=1 (或 n=⌈1+8×S√−12⌉ ,取满足 ∑i≥S 的下界,解二元一次方程得,但是开方的时间开销大于枚举)向上枚举,当 Sn≥S 且 Sn−Smod2=0 时,即为我们所求最小的的 n 。
#include
int main()
{
int S, i;
scanf("%d",&S);
for(i=1;;i++)
if((i*(i+1)/2-S)>=0 && (i*(i+1)/2-S)%2==0){
printf("%d\n",i);
break;
}
return 0;
}
输入一个整数 n(1≤n≤109) ,若以 n 与其他两个整数 m,k(1≤m,k≤1018) 为边长的三条边能构成一个直角三角形,则输出 m,k ,否则输出 −1 。
易知当 n=1,2 时,无法找到满足题意的 m,k 。
当 n>2 时,由于答案可能有多种情况,那么不妨设 n<m<k ,即有 n2+m2=k2 。很容易联想到平方差公式,化为 n2=(k+m)×(k−m) 。寻找规律发现 (3,4,5),(5,12,13),(7,24,25),… , 即当 n 为奇数时,有 k−m=1 一充要条件。故解出 m=n2−12,k=n2+12 。
由此,同样的思路,当 n 为偶数时,令 k−m=2 ,解得 m=n2/4−1,k=n2/4+1
由于此题中 m,k 超出 int 的取值范围,所以需要用 long long int 。
#include
#include
typedef long long ll;
int main()
{
ll n,m,k;
scanf("%I64d",&n);
if(n==1 || n==2){
printf("-1\n");
return 0;
}
if(n%2){
m=(n*n-1)/2;
k=(n*n+1)/2;
}
else{
m=n*n/4-1;
k=n*n/4+1;
}
printf("%I64d %I64d\n",m,k);
return 0;
}
一个节点数为 N(0<N≤109) 的无向完全图,每条边只能走一次。求有多少个经过每一个点的回路。
对于节点数为 N 的无向完全图,每个节点度数为 N−1 ,那么取其中 (N−1)/2 作为出发的边, (N−1)/2 作为返回的边。
注:对于过程的有效性,每条回路使得每个点的度数减 2 。所以整个图在第 i(i=0,1,⋯,N−12) 次遍历前都是联通的。
#include
int main()
{
int n;
while(scanf("%d",&n),n)
printf("%d\n",(n-1)/2);
return 0;
}
有偶数 k(k=2,4,⋯,105) 个小朋友,通过掷硬币的方法吃各有 n=k/2 个的两种汉堡,如果结果为正,吃第一种汉堡,否则吃第二种汉堡。中途若一种被吃完则不再掷。求最后两人吃到同一种汉堡的概率。
求反面——最后两人吃到不同汉堡的情况,那么除了最后一个汉堡外,都进行了一次投掷。可知选取汉堡的情况数为 2×Cn−12n−2 种(由于最后两个汉堡的排列是两种),而每种出现的概率相等,为 0.52n−1 。那么可知最后两人吃到不同汉堡的概率为 p[n]=Cn−12n−2/ 22n−2 。由于直接计算会超出 double 的有效范围,且计算组合数时间复杂度过大,将前后概率相除化为递推式,有 p[n+1]=p[n]×(1−0.5/i) 。
最后输出 1−p[k/2] 即可。
#include
const int MAXN=50005;
double f[MAXN];
int main()
{
f[1]=1;
for(int i=1;i1;i++)
f[i+1]=f[i]*(1-0.5/i);
int n,i;
scanf("%d",&n);
while(n--){
scanf("%d",&i);
printf("%.4lf\n",1-f[i/2]);
}
return 0;
}
在由 n×m(1≤n,m≤1000) 个方格组成的长方形中,至少有一名演员在方格上。如果在某一个方格没有演员,且在此位置放置聚光灯后,在上下左右某个朝向上有演员,那么就称这是个好位置。如果两个位置的所处方格不同或聚光灯朝向不同,则认为两个位置是不同的。求好位置的总数。
考虑时间复杂度为 O(n2) 的方法。如果在一行内依次枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向左照射。同理,如果在一行内逆向枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向右照射。在列上亦是。
#include
const int MAXN=1005;
int mat[MAXN][MAXN];
int main()
{
int n,m,sum=0;
scanf("%d%d",&n,&m);
for(int i=0;ifor(int j=0;jscanf("%d",&mat[i][j]);
for(int i=0;ibool vl=false,vr=false; //vl=ValidLeft,vr=ValidRight
for(int j=0;jif(mat[i][j])
vr=true;
else if(vr)
sum++;
}
for(int j=m-1;j>=0;j--){
if(mat[i][j])
vl=true;
else if(vl)
sum++;
}
}
for(int j=0;jbool vu=false,vd=false; //vu=ValidUp,vd=ValidDown
for(int i=0;iif(mat[i][j])
vd=true;
else if(vd)
sum++;
}
for(int i=n-1;i>=0;i--){
if(mat[i][j])
vu=true;
else if(vu)
sum++;
}
}
printf("%d\n",sum);
return 0;
}
有一个长度为 n(1≤n≤2×105) 的数组 ai(0≤ai≤104) ,问能否对数组经过如下处理后,使整个数组中的数都化为0。
1. a[i] 减去任意偶数个数
2. a[i]−− 且 a[i+1]−−
考虑空间复杂度 O(1) 的方法。设置布尔变量 owned 表示上一个数是否为奇数,初始化为 false 。然后依次读入,若 ai=0 且 owned=true 那么是不可能实现的,直接输出并跳出。否则,若 owned=true 那么 ai 需要减 1 。考察这时的 ai 的奇偶性,若奇,则 owned=true ,若偶,则 owned=false 。
最后只需考察运行完后 owned 的值是否为 false 即可。
#include
int main()
{
int n,a;
bool owned=false,flag=true;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a);
if(!a&&owned){
printf("NO\n");
return 0;
}
if(owned)
a--;
if(a%2)
owned=true;
else
owned=false;
}
if(!owned)
printf("YES\n");
else
printf("NO\n");
return 0;
}