@morehigh
2017-02-25T11:13:29.000000Z
字数 3135
阅读 1069
STL
A - Moo University - Financial Aid
题意:
有C(N <= C <= 100,000)头奶牛,现要招收N(1 <= N <= 19999)头奶牛上大学,给定每头奶牛的智商和所需补助,并给定最大可提供补助和F,0 <= F <= 2000000000,求补助奶牛的智商最大中位数
解题思路:
将奶牛按智商从小到大排序,然后枚举中位数,那么问题就是如何确定中位数左右分别选取n/2头奶牛的最小费用,这个可以通过堆预处理得出,(堆的维护要用到优先队列),正向扫描一遍每次看当前奶牛所需费用是否小于堆顶元素费用,若小于队顶出堆,当前奶牛费用入堆.反向同理,然后枚举一下中位数即可
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
const int inf=10*0x7ffffff;
using namespace std;
long long s1[100050],s2[100050];
struct Node
{
int fir,sec;
bool operator< (const Node &a) const
{
return sec<a.sec;
}
}cow[100050];
bool cmp(Node x,Node y)
{
return x.fir<y.fir;
}
int main()
{
int n,c,f;
// cout<<inf<<" "<<10*0x7ffffff<<endl;
while(~scanf("%d%d%d",&n,&c,&f))
{
for(int i=0;i<c;i++)
scanf("%d%d",&cow[i].fir,&cow[i].sec);
sort(cow,cow+c,cmp);
priority_queue<Node> pq;
int sum=0;
for(int i=0;i<c;i++)
{
s1[i]=inf;
if(i<n/2)
{
pq.push(cow[i]);
sum+=cow[i].sec;
continue;
}
s1[i]=sum;
if(cow[i].sec>=pq.top().sec)continue;
sum-=pq.top().sec;
pq.pop();
sum+=cow[i].sec;
pq.push(cow[i]);
}
sum=0;
while(!pq.empty())pq.pop();
for(int i=c-1;i>=0;i--)
{
s2[i]=inf;
if(i>c-1-n/2)
{
pq.push(cow[i]);
sum+=cow[i].sec;
continue;
}
s2[i]=sum;
if(cow[i].sec>=pq.top().sec)continue;
sum-=pq.top().sec;
pq.pop();
sum+=cow[i].sec;
pq.push(cow[i]);
}
int ans=-1;
for(int i=c-1-n/2;i>=n/2;i--)
{
// cout<<s1[i]<<s2[i]<<" "<<cow[i].sec<<endl;
if(s1[i]+s2[i]+cow[i].sec<=f)
{
ans=cow[i].fir;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
C - HDU Today
题意:
N(0<=N<=10000)是公交车总数,从起始点start到终点end,有n行每一行有一个s,e分别代表车站的站名,和时间t.求坐公交车的最短时间,
解题思路:
首先考虑到要用 dijkstra算法求最短时间,不过每一站的站名是字符串,需要用map将字符串映射为数字,便于处理
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <cmath>
#define inf 0x3f3f3f3f
using namespace std;
char start[100],endd[100],s[100],e[100];
int t,ma[200][200],dis[200],vis[200];
void dijkstra()
{
memset(vis,0,sizeof(vis));
for(int i=1;i<=t;i++)
dis[i]=ma[1][i];
dis[1]=0;
vis[1]=1;
for(int i=1;i<=t;i++)
{
int mm=inf,mk=-1;
for(int j=1;j<=t;j++)
{
if(mm>dis[j]&&!vis[j])
{
mm=dis[j];
mk=j;
}
}
if(mk==-1)
break;
vis[mk]=1;
for(int j=1;j<=t;j++)
{
if(dis[j]>dis[mk]+ma[mk][j]&&!vis[j])
dis[j]=dis[mk]+ma[mk][j];
}
}
}
int main()
{
int n,w;
map<string,int> q;
while(scanf("%d",&n),n!=-1)
{
memset(ma,inf,sizeof(ma));
scanf("%s%s",start,endd);
q.clear();
q[start]=1;
q[endd]=2;
t=3;
for(int i=0;i<n;i++)
{
scanf("%s%s%d",s,e,&w);
if(!q[s])
q[s]=t++;
if(!q[e])
q[e]=t++;
if(ma[q[s]][q[e]]>w)
ma[q[e]][q[s]]=ma[q[s]][q[e]]=w;
}
if(strcmp(start,endd)==0)
{
printf("0\n");
continue;
}
dijkstra();
if(dis[2]==inf)
printf("-1\n");
else
printf("%d\n",dis[2]);
}
return 0;
}
F - Pearls in a Row
题意:
一个长度为n (1 ≤ n ≤ 3·105)的字符串,从中截取一段,如果这一段中有两个相同的数字,则为一个好串,求出有多少个这样的子串和这个子串的左右端点
解题思路:
直接将序列中出现的点标记为1,然后如果下一次出现的话,就记录一下左右端点,并将子串数目加1,加标记的1取消,继续遍历此序列
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
map<int,int> mm;
int a[350000];
struct Node
{
int x,y;
}rang[200005];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
int ll=0,num=0;
for(int i=1;i<=n;i++)
{
if(mm[a[i]]==1)
{
mm.clear();
num++;
rang[num].x=ll+1;
rang[num].y=i;
ll=i;
}else
{
mm[a[i]]=1;
}
}
if(num==0)
printf("-1\n");
else
{
cout<<num<<endl;
for(int i=1;i<num;i++)
{
printf("%d %d\n",rang[i].x,rang[i].y);
}
printf("%d %d\n",rang[num].x,n);
}
return 0;
}