标签:
第一题,不道是什么鬼。。
第二题猜数字。
很多用主席树,我不会,啊啊啊~~~~记得这题有出过吧,想了一发线段树的,把所有的数排序,同时把询问K排序,
做两发遍历,首先从小到大遍历所有的数,单点更新比K小的线段树的点,维护最大值,遇到>=K时则查询一发。
再从大到小遍历,更新比k大的,维护最小值,遇<=K时就查询。比较即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N= 200020;
const int inf=1000000099;
int seg[N*4];
struct No{
int val,pos;
}node[N];
struct Qu{
int l,r,k,index;
}query[N];
int tree_index[N];
int ans[N];
bool cmp1(No a,No b){
if(a.val<b.val) return true;
return false;
}
bool cmp2(Qu a,Qu b){
if(a.k<b.k) return true;
return false;
}
int n,q;
void build1(int rt,int l,int r){
seg[rt]=-inf;
if(l==r){
tree_index[l]=rt; return ;
}
int mid=(l+r)>>1;
build1(rt<<1,l,mid);
build1(rt<<1|1,mid+1,r);
}
void update1(int rt,int val){
seg[rt]=val;
rt/=2;
while(rt){
seg[rt]=max(seg[rt<<1],seg[rt<<1|1]);
rt/=2;
}
}
void build2(int rt,int l,int r){
seg[rt]=inf;
if(l==r){
tree_index[l]=rt; return ;
}
int mid=(l+r)>>1;
build2(rt<<1,l,mid);
build2(rt<<1|1,mid+1,r);
}
void update2(int rt,int val){
seg[rt]=val;
rt/=2;
while(rt){
seg[rt]=min(seg[rt<<1],seg[rt<<1|1]);
rt/=2;
}
}
int queryMax(int rt,int l,int r,int L,int R){
if(l<=L&&R<=r){
return seg[rt];
}
int mid=(L+R)>>1;
if(l>=mid+1){
return queryMax(rt<<1|1,l,r,mid+1,R);
}
else if(r<=mid) return queryMax(rt<<1,l,r,L,mid);
return max(queryMax(rt<<1,l,r,L,mid),queryMax(rt<<1|1,l,r,mid+1,R));
}
int queryMin(int rt,int l,int r,int L,int R){
if(l<=L&&R<=r){
return seg[rt];
}
int mid=(L+R)>>1;
if(l>=mid+1){
return queryMin(rt<<1|1,l,r,mid+1,R);
}
else if(r<=mid) return queryMin(rt<<1,l,r,L,mid);
return min(queryMin(rt<<1,l,r,L,mid),queryMin(rt<<1|1,l,r,mid+1,R));
}
int main(){
int T,icase=0;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&node[i].val);
node[i].pos=i;
}
for(int i=1;i<=q;i++){
scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k);
query[i].index=i;
ans[i]=inf;
}
sort(node+1,node+1+n,cmp1);
sort(query+1,query+1+q,cmp2);
build1(1,1,n);
int j=1;
for(int i=1;i<=q;i++){
for(;node[j].val<=query[i].k&&j<=n;j++){
update1(tree_index[node[j].pos],node[j].val);
}
int t=queryMax(1,query[i].l,query[i].r,1,n);
if(t==-inf) continue;
ans[query[i].index]=min(ans[query[i].index],query[i].k-t);
}
// for(int i=1;i<=q;i++)
// printf("%d\n",ans[i]);
j=n;
build2(1,1,n);
for(int i=q;i>0;i--){
for(;node[j].val>=query[i].k&&j>0;j--){
update2(tree_index[node[j].pos],node[j].val);
}
int t=queryMin(1,query[i].l,query[i].r,1,n);
if(t==inf) continue;
ans[query[i].index]=min(ans[query[i].index],t-query[i].k);
}
printf("Case #%d:\n",++icase);
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
}
return 0;
}
第三题,机器人。
感谢斌神。知道,对于同一种颜色,归并后相对顺序是不对的。处理出对某个颜色相对于某颜色,所有块要移动到最后位置经过的步数,斌神叫逆序。然后,优化一下,对于某种颜色,它之前已加入K种颜色(状态压缩),它要移动到最后,经过的步数。枚举各种状态dp[k]为该状态变颜色相连要的步数,枚举状态内的颜色,求出在该状态下,该颜色移动到最末所需的最少步数,比较。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const LL inf=1100000000000LL;
const int MAXN=100050;
int robot[MAXN];
LL dp[1<<17];
int b[20]; LL num[20][20]; LL f[20][1<<17];
int bit[20],loc[1<<17];
int main(){
int T,icase=0;
bit[0]=1; loc[bit[0]]=0;
for(int i=1;i<17;i++){
bit[i]=(bit[i-1]*2);
loc[bit[i]]=i;
}
scanf("%d",&T);
while(T--){
int n,k;
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&robot[i]);
robot[i]--;
}
memset(b,0,sizeof(b));
memset(num,0,sizeof(num));
for(int i=n-1;i>=0;i--){
for(int j=0;j<k;j++){
if(robot[i]!=j){
num[robot[i]][j]+=b[j];
}
}
b[robot[i]]++;
}
int tot=(1<<k);
for(int j=0;j<k;j++){
f[j][0]=0;
for(int i=1;i<tot;i++){
int t=i&(-i);
f[j][i]=f[j][i^t]+num[j][loc[t]];
}
}
for(int i=0;i<tot;i++)
dp[i]=inf;
dp[0]=0;
for(int i=0;i<tot;i++){
if(dp[i]==inf) continue;
for(int j=0;j<k;j++){
if(bit[j]&i) continue;
dp[i|bit[j]]=min(dp[i|bit[j]],dp[i]+f[j][i]);
}
}
printf("Case #%d: %lld\n",++icase,dp[tot-1]);
}
return 0;
}
第四题。可以知道,若城市被包塔包围,则它至多在一个三角形内。而激活塔的费用远小于城市的,所以优先激活塔。对塔求一个凸包,看哪些点在凸包内,然后计算塔的最小环能把那些城市全包含,floyd即可,黙认为逆时针即可,计算那些城市是否在边的左边,在则可以连边,不在就不能。然后就计算即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN=110;
const int inf=10000000;
struct Point{
int x,y;
}cities[MAXN],tower[MAXN],anscity[MAXN];
int n,m,top,g,p;
int pexres[MAXN];
bool cmp(Point a,Point b){
if(a.y==b.y) return a.x<b.x;
return a.y<b.y;
}
bool multi(Point sp,Point ep,Point op){
return (sp.x-op.x)*(ep.y-op.y)>=(ep.x-op.x)*(sp.y-op.y);
}
int Multi(Point p1,Point p2,Point p0){
return (p1.x-p0.x)*(p2.y-p0.y)-(p2.x-p0.x)*(p1.y-p0.y);
}
int inside(int index){
int i; int now;
for(i=0;i<top;i++){
now=Multi(tower[pexres[i]],tower[pexres[(i+1)%top]],cities[index]);
if(now<=0) return 0;
}
return 1;
}
void Graham(){
int i,len;
top=1;
sort(tower,tower+n,cmp);
if(n==0) return ; pexres[0]=0;
if(n==1) return ; pexres[1]=1;
if(n==2) return ; pexres[2]=2;
for(i=2;i<n;i++){
while(top&&multi(tower[i],tower[pexres[top]],tower[pexres[top-1]])) top--;
pexres[++top]=i;
}
len=top;
pexres[++top]=n-2;
for(i=n-3;i>=0;i--){
while(top!=len&&multi(tower[i],tower[pexres[top]],tower[pexres[top-1]])) top--;
pexres[++top]=i;
}
}
int d[MAXN][MAXN];
bool check(int i,int j,int cnt){
for(int k=0;k<cnt;k++){
int now=Multi(tower[i],tower[j],anscity[k]);
if(now<=0) return false;
}
return true;
}
int main(){
int T,icase=0;
scanf("%d",&T);
while(T--){
scanf("%d%d%d%d",&n,&m,&g,&p);
for(int i=0;i<n;i++){
scanf("%d%d",&tower[i].x,&tower[i].y);
}
for(int i=0;i<m;i++)
scanf("%d%d",&cities[i].x,&cities[i].y);
printf("Case #%d: ",++icase);
if(n<3){
printf("%d\n",g*m);
continue;
}
Graham();
// for(int i=0;i<=top;i++)
// cout<<pexres[i]<<endl;
int cnt=0;
for(int i=0;i<m;i++){
if(inside(i)){
anscity[cnt++]=cities[i];
}
}
int len=inf;
if(cnt){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
d[i][j]=inf;
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j) continue;
if(check(i,j,cnt)){
d[i][j]=1;
}
}
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
for(int k=0;k<n;k++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
for(int i=0;i<n;i++)
len=min(len,d[i][i]);
}
if(cnt==0) len=0;
printf("%d\n",(m-cnt)*g+p*len);
}
return 0;
}
标签:
原文地址:http://www.cnblogs.com/jie-dcai/p/4523919.html