A.简单求和 POJ1844
题目大意
找出最小的
n
,使对于给定的
成立。
思路
首先知
n
的必要条件为
所以当我们从
n=1
(或
n=⌈1+8×S√−12⌉
,取满足
∑i≥S
的下界,解二元一次方程得,但是开方的时间开销大于枚举)向上枚举,当
Sn≥S
且
Sn−Smod2=0
时,即为我们所求最小的的
n
。
代码
#include<cstdio>
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;
}
B.悉宇大大的问题 CodeForces707C
题目大意
输入一个整数
思路
易知当
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
为奇数时,有
由此,同样的思路,当
n
为偶数时,令
由于此题中
m,k
超出
int
的取值范围,所以需要用
long long int
。
代码
#include<cstdio>
#include<cstdio>
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;
}
C.老陶的幸福生活 HDU1273
题目大意
一个节点数为 N(0<N≤109) 的无向完全图,每条边只能走一次。求有多少个经过每一个点的回路。
思路
对于节点数为
N
的无向完全图,每个节点度数为
注:对于过程的有效性,每条回路使得每个点的度数减
2
。所以整个图在第
代码
#include<cstdio>
int main()
{
int n;
while(scanf("%d",&n),n)
printf("%d\n",(n-1)/2);
return 0;
}
D.小朋友吃汉堡 UVA557
题目大意
有偶数 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<cstdio>
const int MAXN=50005;
double f[MAXN];
int main()
{
f[1]=1;
for(int i=1;i<MAXN-1;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;
}
E.舞台灯光问题 CodeForces738B
题目大意
在由 n×m(1≤n,m≤1000) 个方格组成的长方形中,至少有一名演员在方格上。如果在某一个方格没有演员,且在此位置放置聚光灯后,在上下左右某个朝向上有演员,那么就称这是个好位置。如果两个位置的所处方格不同或聚光灯朝向不同,则认为两个位置是不同的。求好位置的总数。
思路
考虑时间复杂度为 O(n2) 的方法。如果在一行内依次枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向左照射。同理,如果在一行内逆向枚举,一旦有演员出现,那么其后的空地都可以放置聚光灯向右照射。在列上亦是。
代码
#include<cstdio>
const int MAXN=1005;
int mat[MAXN][MAXN];
int main()
{
int n,m,sum=0;
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
scanf("%d",&mat[i][j]);
for(int i=0;i<n;i++){
bool vl=false,vr=false; //vl=ValidLeft,vr=ValidRight
for(int j=0;j<m;j++){
if(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;j<m;j++){
bool vu=false,vd=false; //vu=ValidUp,vd=ValidDown
for(int i=0;i<n;i++){
if(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;
}
F-Boss买披萨 CodeForces731B
题目大意
有一个长度为
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
。考察这时的
最后只需考察运行完后
owned
的值是否为
false
即可。
代码
#include<cstdio>
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;
}