标签: nowcoder
传送门
https://www.nowcoder.com/acm/contest/112#question
A.最小化价格
贪心做的。贪心策略:从价格最低的开始分配,然后对于每个地点把它所能容纳的最大的队伍分配给他。(PS:看到钰神的贪心策略是这样的,从人数最多的队伍开始分配,每次把能够容纳这个队伍的价格最低的分配给他,优先队列就可以实现)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
const int maxn=200050;
typedef long long ll;
const ll MOd=1e9+7;
struct node{
int x,p;
bool operator <(const node&y)const{
if(p!=y.p) return p<y.p;
return x>y.x;
}
}b[maxn];
int a[maxn];
bool cmp(int a,int b){
return a>b;
}
map<int,int> mp;
int main(){
int n,m;
scanf("%d%d", &n,&m);
int M=0;
for(int i = 0; i < n; ++i){
int x;
scanf("%d", &x);
M=max(M,x);
mp[x]++;
}
for(int i = 0; i < m; ++i){
scanf("%d%d", &b[i].x,&b[i].p);
}
sort(b,b+m);
int sum=0;
for(int i = 0; i < m; ++i){
map<int,int>::iterator it=mp.lower_bound(b[i].x);
if(it->first == b[i].x) it->second --,sum+=b[i].p;
else if(it==mp.begin()) continue;
else{
it--;
it->second --;
sum+=b[i].p;
}
if(it->second == 0){
mp.erase(it);
}
}
if(mp.size()) cout << -1 << endl;
else cout << sum << endl;
}
B.车辆安排
#include <iostream>
#include <cstdio>
using namespace std;
int a[10];
int main(){
int n;
scanf("%d", &n);
for(int i = 0; i < n; ++i){
int x;
scanf("%d", &x);
a[x]++;
}
int ans=a[5];
if(a[1]>a[4]) a[1]-=a[4],ans+=a[4],a[4]=0;
else a[1]=0,ans+=a[4],a[4]=0;
if(a[2]>a[3]) a[2]-=a[3],ans+=a[3],a[3]=0;
else{
ans+=a[2],a[3]-=a[2],a[2]=0;
if(a[1]>2*a[3]) ans+=a[3],a[1]-=2*a[3],a[3]=0;
else ans+=a[3],a[1]=0,a[3]=0;
}
if(2*a[1]<a[2]){
ans+=a[1];
a[2]-=a[1]*2;
a[1]=0;
}
else{
ans+=a[2]/2;
a[1]-=a[2]/2;
a[2]-=a[2]/2*2;
}
if(a[2]&&a[1]==0){
ans+=(a[2]+1)/2;
}
else{
int x=a[1]+a[2]*2;
ans+=(x/5);
if(x%5) ans++;
}
cout << ans <<endl;
}
C.出队
递归模拟即可,时间复杂度(O(log_2x))
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll f(ll n,ll x){
if(x&1) return (x+1)/2;
ll y=x/2-1;
if(y==0) y=n/2;
if(n&1) return n/2+1+f(n/2,y);
return n/2+f(n/2,x/2);
}
int main(){
ll n,q;
scanf("%lld%lld", &n,&q);
while(q--){
ll x;
scanf("%lld", &x);
cout << f(n,x) << endl;
}
return 0;
}
D.数字串
对于每个数字都建立一个树状数组,每次修改时先减去他的影响,再加上新数的影响。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=100050;
int a[10][maxn],n;
void update(int *p,int x,int val){
while(x<=n){
p[x]+=val;
x += x&-x;
}
}
int query(int *p,int x){
int ans=0;
while(x){
ans+=p[x];
x-=x&-x;
}
return ans;
}
char s[maxn];
int main(){
scanf("%s", s+1);
n=strlen(s+1);
int q,l,r;
scanf("%d%d%d", &q,&l,&r);
ll sum=0;
for(int i = n; i >= 1; --i){
update(a[s[i]-'0'],i,1);
for(int j = 0; j < s[i]-'0'; ++j){
sum+=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
}
}
while(q--){
int i,x;
scanf("%d%d", &i,&x);
int y=s[i]-'0';
s[i]=x+'0';
for(int j = 0; j < y; ++j){
sum-=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
}
for(int j = 9; j > y; --j){
sum-=query(a[j],max(i-l+1,0))-query(a[j],max(0,i-r));
}
update(a[y],i,-1);
for(int j = 0; j < x; ++j){
sum+=query(a[j],min(i+r-1,n))-query(a[j],min(n,i+l-2));
}
for(int j = 9; j > x; --j){
sum+=query(a[j],max(i-l+1,0))-query(a[j],max(0,i-r));
}
update(a[x],i,1);
printf("%lld
", sum);
}
return 0;
}
E.小W的斜率
分析
我们要求两个点连线斜率最接近(P/Q)的。可以考虑这样,在((Q,P))方向和((P,-Q))建立新的坐标轴,那么沿着((P,-Q))方向排列所有的点,排列后相邻的点之间的连线的斜率一定是最接近(P/Q)的。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int maxn=1000050;
int n,p,q;
struct node{
int x,y;
bool operator < (const node&t)const{
return (ll)p*x-(ll)q*y<(ll)p*t.x-(ll)q*t.y;
}
}a[maxn];
int main(){
scanf("%d%d%d", &n,&p,&q);
for(int i = 0; i < n; ++i) scanf("%d%d", &a[i].x,&a[i].y);
sort(a,a+n);
double m=1e20;
int P,Q;
for(int i = 1; i < n; ++i){
double t=(double)(a[i].y-a[i-1].y)/(double)(a[i].x-a[i-1].x)-(double)p/q;
if(fabs(t)<m){
m=fabs(t);
P=a[i].y-a[i-1].y;
Q=a[i].x-a[i-1].x;
}
}
if(P<0) P=-P,Q=-Q;
int d=__gcd(P,Q);
P/=d,Q/=d;
printf("%d/%d
", P,Q);
}
F.下棋
留坑