传送门:A. Raising Bacteria (水题)
二进制中的1的个数,在数量上是恰好对应答案的。
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " "
#define pl(x) cout << #x << "= " << x << endl;
#define Memset(x, a) memset(x, a, sizeof(x))
#define ll __int64
using namespace std;
const int inf=0x3f3f3f3f;
int n;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
n=read();
int cnt=0;
while(n>0){
if(n&1)cnt++;
n>>=1;
}
cout<<cnt<<endl;
return 0;
}
传送门:B. Finding Team Member (模拟)
第一个数据
6
1 2
3 4 5
想成
0 6 1 3
6 0 2 4
1 2 0 5
3 4 5 0
Aij表示的是i和j组队的力量值 找最大值是6 A12
所以1选2,2选1
然后不看第一行第一列第二行第二列再找最大值,最大值是5 A34
所以3选4 ,4选3
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " "
#define pl(x) cout << #x << "= " << x << endl;
#define Memset(x, a) memset(x, a, sizeof(x))
#define ll __int64
using namespace std;
const int inf=0x3f3f3f3f;
int n;
int b[1000];
int a[1000][1000];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
n=read();
for(int i=2; i<=2*n; i++){
for(int j=1; j<i; j++){
a[i][j]=read();
}
}
int x,y;
for(int k=1; k<=n; k++){
int maxn=0;
for(int i=2; i<=2*n; i++){
for(int j=1; j<i; j++){
if(a[i][j]>maxn){
maxn=a[i][j];
x=i;y=j;
b[x]=y;b[y]=x;
}
}
}
for(int i=1; i<=2*n; i++){
a[i][x]=0;a[x][i]=0;
a[i][y]=0;a[y][i]=0;
}
}
for(int i=1; i<=2*n; i++)printf("%d%c",b[i],i==2*n?'\n':' ');
return 0;
}
传送门:C. A Problem about Polyline (趣题)
#include <bits/stdc++.h>
#define pr(x) cout << #x << "= " << x << " "
#define pl(x) cout << #x << "= " << x << endl;
#define Memset(x, a) memset(x, a, sizeof(x))
#define ll __int64
using namespace std;
const ll inf=0x3f3f3f3f;
int a,b;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll bin(ll l,ll r){
ll res=-1;
while(l<=r){
ll m=(l+r)>>1;
double x=(a+b)*1.0/(2*m);
if(x>=b)l=m+1,res=m;
else r=m-1;
}
return res;
}
int main(){
a=read();b=read();
if(b>a)printf("-1");
else{
ll k=bin(1LL,inf);
printf("%.9lf\n",(a+b)*1.0/(2*k));
}
return 0;
}
方法二就是手推式子, 首先这题答案如果存在解x的话,点(a,b)落在斜率为-1的直线上面x最小
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b;
cin>>a>>b;
if(b>a){ puts("-1");return 0; }
printf("%.9lf",(a+b) / (2.0 * ((a+b) / (2*b)) ) );
return 0;
}
传送门:D. "Or" Game (好题)
首先,一定是处理转化为二进制之后位数最多的几个数(连续乘以k次x),因为x至少为2,所以位数最多的几个数乘以x之后一定向左移动一位,肯定比其他的数大
其次,为什么不一定是处理最大的数呢,比如
2 1 2
9 12
如果处理12之后答案是25,而处理9之后答案是30,因为12的二进制左移一位之后会和9的二进制有重合,而9的二进制后移一位则不会有这种情况发生
所以只要枚举处理这n个数中的哪个就行了,如果暴力的话最小是n*n*logK,
这里用了一点特殊的技巧,处理出了前缀的或和和后缀的或和,这样的话可以在n*logK(使用快速幂)的时间复杂度内完成(因为这题K很小,所以代码里就没有快速幂)
#include <bits/stdc++.h>
#define ll __int64
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=200010;
ll a[maxn],pre[maxn],nex[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main(){
int n,k,x;
n=read();k=read();x=read();
for(int i=1; i<=n; i++){
a[i]=read();
pre[i]=pre[i-1]|a[i];
}
for(int i=n; i>=1; i--){
nex[i]=nex[i+1]|a[i];
}
ll ans=0;
for(int i=1; i<=n; i++){
for(int j=0 ;j<k ;j++){
a[i]*=x;
ans=max(ans,pre[i-1]|a[i]|nex[i+1]);
}
}
cout<<ans<<endl;
return 0;
}
传送门:E. Weakness and Poorness (三分+最大子段和)
题意:
题目定义了两个变量:
poorness 表示一个区间内和的绝对值。
weakness 表示一个所有区间最大的poornesss
题目要求你求一个 x 使得
a1 − x, a2 − x, ..., an − x 这个序列的 weakness 最小
输出最小的 weakness
思路:
设f(x)为取x时的最大子段和,f(x)是先减后增的,于是可以用三分法求最值
至于最大连续子序列和最小连续子序列的求法,只要2遍最大连续和就可以了,第1遍后将每个数取反,这样第2
遍也是一个最大连续和。
还有一种方法是二分,随着x的递增,序列的最大连续子序列和肯定在减小,因为每个数都减小了,其最小连
续子序列和的绝对值肯定是增大趋势,都是单调的,于是将最大连续子序列的和和最小连续子序列和的绝对值分开记录,就可二分,会有点麻烦。
ps:这题精度卡的严,1e-11会wa,1e-12会T,三分100次就过了,所以建议还是用for100次,比较保稳。
#include<bits/stdc++.h>
using namespace std;
const double eps=3e-12;
double a[200010],b[200010];
int n;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
double MaxSum(double c[]){
double ans=0,tmp=0;
for(int i=1; i<=n; i++){
tmp+=c[i];
if(tmp<0)tmp=0;
ans=max(ans,tmp);
}
return ans;
}
double calc(double x){
for(int i=1; i<=n; i++){
b[i]=a[i]-x;
}
double ans1=MaxSum(b);
for(int i=1; i<=n; i++){
b[i]=-b[i];
}
double ans2=MaxSum(b);
return max(ans1,ans2);
}
double ternary(){
double l=-1e4,r=1e4;
double lm,rm;
for(int i=0; i<100; i++){ //或者是while(l+eps<r)
double d=(r-l)/3.0;
lm=l+d,rm=r-d;
double v1=calc(lm);
double v2=calc(rm);
if(v1<v2)r=rm;
else l=lm;
}
return calc(r);
}
int main(){
n=read();
for(int i=1; i<=n; i++){
a[i]=read();
}
printf("%.15lf",ternary());
return 0;
}
L:第一题的位运算,C题括号较多要多用空格隔开,D题的前后缀或和