本次考试三道题的难度适中,T1没有认真分析,把情况考虑全面,就炸了。T2的话主要是二分的check()写错了;T3是异或的套路题然而我并不知道这个套路
T1 :
题目描述:
给出 n 个数。请找出一个排列使得相邻两个数的差的绝对值的和最大。请求出这个最大值。
题解:
通过样例数据我们可以发现:
n为偶数时,只存在一种情况 ,对于一个数列 1 4 2 3 ,ans=-1+4+4-2-2+3
n为奇数时,存在两种情况,分别是将最大的数放在中间,将最小的数放在中间,例:
对于数列 1 5 2 4 3 当前的 ans=-1+5+5-2-2+4+4-3
对于数列 4 2 5 1 3 当前的 ans=+4-2-2+5+5-1-1+3
我们不难发现,对于两种情况我们分别把小的一半中的最大的两个放两边为最优解,和把大的一般的最小的两个数放两边为最优解,最后在取max就行了
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
using namespace std;
int n,sum,T,a[60],sum0,sum1;
//---------------------
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
//---------------------
int main(){
//freopen("sequence.in","r",stdin);
//freopen("sequence.out","w",stdout);
T=Readint();
for(int i=1;i<=T;i++){
cout<<"Case "<<i<<": ";
memset(a,0,sizeof(a));
sum=0;
n=Readint();
for(int j=1;j<=n;j++) a[j]=Readint();
sort(a+1,a+1+n);
if(n==1) cout<<sum<<endl;
else {
if(n%2==0){
sum0=a[n/2],sum1=a[n/2+1];
for(int i=1;i<n/2;i++) sum0+=2*a[i];
for(int i=n/2+2;i<=n;i++) sum1+=2*a[i];
sum=sum1-sum0;
}
else{
sum0=0,sum1=a[n/2+1]+a[n/2+2];
for(int i=1;i<=n/2;i++) sum0+=2*a[i];
for(int i=n/2+3;i<=n;i++) sum1+=2*a[i];
sum=sum1-sum0;
sum1=0,sum0=a[n/2]+a[n/2+1];
for(int i=1;i<n/2;i++) sum0+=2*a[i];
for(int i=n/2+2;i<=n;i++) sum1+=2*a[i];
sum=max(sum,sum1-sum0);
}
cout<<sum<<endl;
}
}
return 0;
}
T2:
题目描述:
今天是ABC的生日,他制作了一个巧克力蛋糕!你可以把它理解成一个有 R×C 个小格子组成的矩形。每个格子上都有一些巧克力 chips ,第 i 行,第 j 列的格子上有 A[i][j] 个巧克力 chips 。
有 A×B 个人要出席 ABC 的生日晚会(包括ABC自己),每个人都想得到一块蛋糕。于是他想要把他的蛋糕切成 A×B 个小块。首先,他先横着切(A-1)刀,蛋糕就变成了 A 条,然后,对于每一条,他都纵着切(B-1)刀,就的到了(A×B)个小块。为了体现自己的大度, ABC 决定最后选蛋糕,而 ABC 的朋友就不会这么想了,他们总是拿走巧克力最多的蛋糕,所以,ABC 得到的蛋糕永远是巧克力最少的那一块。
聪明的 ABC 很喜欢吃巧克力,他想得到更多的巧克力,但是他正忙着准备自己的生日晚会,于是他来寻求你的帮助,希望你不要让他失望。
题解:
题目看完,正常人都能看出是二分,而且都知道直接贪心check即可,然而考试的时候我并没有想出这个贪心的方法..
回到正题,由题意可知,每次横着切是必定会把蛋糕彻底切开,所以我们贪心的时候只需要对于每一横排,看它能不能被切成B块,如果不能的话,再加上下一排,最后再看看排数有没有A 即可
#include<cstdio>
#include<algorithm>
#include<iomanip>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<cctype>
using namespace std;
int n,m,a,b,val[520][520];
long long L,R,tmp[520];
//---------------------
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
//---------------------
inline bool check(long long x){
memset(tmp,0,sizeof(tmp));
int cnt0=0,cnt1,w;
for(int i=1;i<=n;i++){
cnt1=w=0;
for(int j=1;j<=m;j++) tmp[j]+=val[i][j];
for(int j=1;j<=m;j++){
w+=tmp[j];
if(w>=x) cnt1++,w=0;
}
if(cnt1>=b){
memset(tmp,0,sizeof(tmp));
cnt0++;
}
if(cnt0>=a) return true;
}
return cnt0>=a;
}
//---------------------
int main(){
//freopen("cut.in","r",stdin);
//freopen("cut.out","w",stdout);
n=Readint(),m=Readint(),a=Readint(),b=Readint();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
val[i][j]=Readint();
R+=val[i][j];
}
}
while(L<=R){
long long mid=(L+R)>>1;
if(check(mid)) L=mid+1;
else R=mid-1;
}
cout<<R<<endl;
return 0;
}
T3:
题目描述:
求一棵带边权的树的一条最大 Xor 路径的值。这里的“路径”不一定从根到叶子结点,中间一段路径只要满足条件也可以。
其实这道题就是一个在一个二进制tri树上的贪心,前提是我考试的时候要先知道Xor路径是什么意思。
首先, Xor路径就是路径上的每条边的长度都与前面的值异或一下的结果。
然后,你要知道 a^b^a=b 得到,a^b^b=a;
所以对于树上的任意两点间的路径的异或值,等于他们到根节点的异或值再异或一下,因为lca以上的部分被抵消了;
当这些都已经知道了,就只剩下了tri树上的套路了:
将每个点到根节点的异或路径的值都用二进制加入到tri树中,由异或的性质我们可以知道,要想两条路径的异或值最大,对于一条已知的路径,我们只需要在tri树上从根节点开始出发,每次尽量找以当前位不同的数继续走(比如当前是1,就找0,反之亦然)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<cctype>
using namespace std;
//---------------------
const int N = 100005,L=35;
struct node{
int son[2];
}tri[N*L];
int n,len,mx;
int tot,first[N],to[N<<1],next[N<<1],val[N<<1];
int dis[N];
//---------------------
inline int Readint(){
int i=0,f=1;char ch;
for(ch=getchar();(ch<'0'||ch>'9')&&ch!='-';ch=getchar());
if(ch=='-') f=-1,ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) i=(i<<1)+(i<<3)+ch-'0';
return i*f;
}
//---------------------
inline void add(int x,int y,int z){
next[++tot]=first[x];first[x]=tot;
to[tot]=y;val[tot]=z;
}
//---------------------
inline void dfs(int now,int fa){
for(int e=first[now];e;e=next[e]){
int v=to[e];
if(v!=fa){
dis[v]=dis[now]^val[e];
dfs(v,now);
}
}
}
//---------------------
inline void Insert(int val){
int po=0;
for(int i=len-1;i>=0;i--){
int t=(val>>i)&1;
if(!tri[po].son[t]) tri[po].son[t]=++tot;
po=tri[po].son[t];
}
}
//---------------------
inline int find(int val){
int po=0;
for(int i=len-1;i>=0;i--){
int t=(val>>i)&1;
if(tri[po].son[t^1]) po=tri[po].son[t^1],val|=(1<<i);
else po=tri[po].son[t],val^=(t<<i);
}
return val;
}
//---------------------
int main(){
// freopen("xor.in","r",stdin);
int x,y,z;
n=Readint();
for(int i=1;i<n;i++){
x=Readint(),y=Readint(),z=Readint();
mx=max(mx,z);
add(x,y,z); add(y,x,z);
}
dfs(1,0);
while(mx) mx>>=1,len++;
tot=0;
for(int i=1;i<=n;i++) Insert(dis[i]);
for(int i=1;i<=n;i++){
dis[i]=find(dis[i]);
mx=max(mx,dis[i]);
}
cout<<mx<<endl;
return 0;
}