1011Segment Tree with Pruning(线段树剪枝)
题目大意:给定一棵区间 [ 1 , n ] [1,n][1,n] 的线段树,其中最长的叶子结点区间长度不超过 k kk ,求出线段树的结点数。
解题思路:分为前最后一层与非最后一层来进行计算,非最后一层的一定是一个完全二叉树部分,结点数为2^n-1,最后加上最后一层的节点数即为答案。
代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int t,l1=0,l2=0;
ll n,k,sum[62],x,ans,lp;
//获取最高位
ll hight_bit(ll x){
x= x|(x>>1);
x= x|(x>>2);
x= x|(x>>4);
x= x|(x>>8);
x= x|(x>>16);
x= x|(x>>32);
x= x|(x>>64);
return (x+1) >> 1;
}
int main(){
sum[0]=1;
for(int i=1;i<=61;i++){
sum[i]=sum[i-1]*2;
}
cin>>t;
while(t--){
cin>>n>>k;
x=n;lp=1;l1=1;l2=1;
if(k==1){
cout<<n*2-1<<endl;
continue;
}
while(x>k){
x=(x+1)/2;
l1++;
}
while(n-lp+1>k){
lp=(lp+n)/2+1;
l2++;
}
if(l1==l2){
ans=sum[l1]-1; // 完全
}
else{ // 不完全
ans=hight_bit(n/k)*2-1; // 上半部分是完全二叉树
ans+=(n-hight_bit(n/k)*k)*2; // 每个区间超过k的结点在最下面一层长出两个叶子
}
cout<<ans<<endl;
}
return 0;
}
1007Photoshop Layers
题目大意:
利用(R,G,B)这样的一个组合来表示颜色背景。图层的颜色是 ( R = 0 , G = 0 , B = 0 )(R=0,G=0,B=0)(R=0,G=0,B=0) 。按顺序给出若干正常图层和渐变图层,正常图层会直接覆盖之前的图层,渐变图层(Ri,Gi,Bi) (Ri,Gi,Bi)(Ri,Gi,Bi) 会把颜色(Rp,Gp,Bp) 变成(min(Rp+Ri,255),min(Gp+Gi,255),min(Bp+Bi,255))。
进行 q次询问,每次询问 [li,ri]图层的颜色。
解题思路:用一个数组来记录正常图层,每次给出区间(l,r)时找到r左边的第一个正常图层,则中间就全部为渐变图层,利用前缀和对其进行处理,根据题意与255最小值进行输出。
#include<bits/stdc++.h>
using namespace std;
struct node {
int b,v[3];
} p[100005];
int t,n,m,nt[100005],pr[100005][3];
int main() {
scanf("%d",&t);
while(t--) {
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++) nt[i]=0;
for(int i=1;i<=n;i++) pr[i][0]=pr[i][1]=pr[i][2]=0;
for(int i=1,v;i<=n;i++) {
scanf("%d %X",&p[i].b,&v); // 读入16进制
p[i].v[0]=v>>16;
p[i].v[1]=(v>>8)-(p[i].v[0]<<8);
p[i].v[2]=v-(p[i].v[1]<<8)-(p[i].v[0]<<16);
if(p[i].b==1) { // 正常图层
pr[i][0]=pr[i][1]=pr[i][2]=0;
nt[i]=i;
} else { // 渐变图层
nt[i]=nt[i-1];
pr[i][0]=pr[i-1][0]+p[i].v[0];
pr[i][1]=pr[i-1][1]+p[i].v[1];
pr[i][2]=pr[i-1][2]+p[i].v[2];
}
}
for(int i=1,l,r;i<=m;i++) {
scanf("%d %d",&l,&r);
if(nt[r]<l) {
printf("%02X%02X%02X\n",
min(pr[r][0]-pr[l-1][0],255),
min(pr[r][1]-pr[l-1][1],255),
min(pr[r][2]-pr[l-1][2],255)); // 输出16进制
} else {
printf("%02X%02X%02X\n",
min(p[nt[r]].v[0]+pr[r][0],255),
min(p[nt[r]].v[1]+pr[r][1],255),
min(p[nt[r]].v[2]+pr[r][2],255));
}
}
}
}
1004Game on Plane
输入:
2
2
1 1 2 2
0 0 2 3
3
1 1 2 2
1 1 2 2
3 2 5 4
输出:
0
1
0
0
0
题目大意:给出n条直线,Alice将选择其中的k条记为l1,l2,l3,l4......lk;Bob将选择其中的一条,使得这一条直线与Alice选择的有尽可能多的交点。
求解k=1,2,3...n时的交点数目。
解题思路:很容易可以想到Alice要使得交点数目尽可能的少,她应该尽量选择斜率不同的直线,Bob要得到尽可能少的交点,因此,他每次应该避开斜率出现最多的直线(与其平行)。
因此,对于所有的点,我们计算斜率并将其化到最简,对斜率进行排序,从最小的斜率开始,将斜率相同的直线储存到数组k【d】当中,且每次都从k【0】开始储存。记录斜率我们可以使用pair,分别记录分子与分母。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>P; // 相当于结构体
const int N=100005;
int Case,n,i,j,k,f[N];
P a[N]; // 保存分数
inline int abs(int x){return x>0?x:-x;}
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main(){
scanf("%d",&Case);
while(Case--){
scanf("%d",&n);
for(i=1;i<=n;i++){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
int dx=x2-x1,dy=y2-y1;
if(dx==0)dy=1; // 斜率不存在
else if(dy==0)dx=1; // 斜率为0
else{
if(dx<0)dx=-dx,dy=-dy; // 规定分母非负
int d=gcd(abs(dx),abs(dy));
dx/=d,dy/=d; // 化最简分数
}
a[i]=P(dx,dy);
}
sort(a+1,a+n+1); // pair可以直接sort
for(i=1;i<=n;i++)f[i]=0; // 初始化f数组
for(i=1;i<=n;i=j){ // i指向一个斜率
for(j=i+1;j<=n&&a[i]==a[j];j++); // j指向i后面第一个 数值与i指向的斜率不同的 斜率
for(k=1;k<=j-i;k++)f[k]++;
}
for(i=j=1;i<=n;i++){
while(f[j]==0)j++; // 跳过取完的数组
f[j]--; // 从f[j]取一个,此时最多j条平行线
printf("%d\n",i-j);
}
}
}