[풀이] struct P{ int id,t,pos; } id : id, t : 계산이 끝나는 시간, pos :계산대의 위치 위와 같이 구조체를 정의해줍니다. 그리고 우선순위큐의 comparator 객체를 정의하여 끝나는 시간 t가 작을수록 , 출구에 가까운 계산대 (pos가 클수록) top에 오도록 해줍니다.
그 뒤 매 루프마다 끝나는 시간이 빠른 모든 원소들을 pop 해준 뒤 ans vector에는 id를 저장해줍니다. 출구쪽부터 pop되기 때문에 이 순서로 ans vector에 저장해주면 됩니다.
rp vector에는 pop되는 순서대로 pos를 저장해줍니다. 이 rp vector를 뒤집은 뒤 반대로 순회하면서 나온 pos에 순차적으로 고객들을 push해줍니다. 시간은 현재 pop된 t+(고객의 물건 수)를 해주면 끝나는 시간을 넣어줄 수 있습니다.
위 과정을 반복하면서 ans vector를 채워주면 정답을 구할 수 있습니다.
#include <cstdio>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
int N,k;
pair<int,int> a[1000000];
struct P{
int id,t,pos;
};
struct cmp{
bool operator()(P& a,P& b){
if(a.t > b.t) return true;
else if(a.t == b.t){
if(a.pos<b.pos) return true;
}
return false;
}
};
int main(){
scanf("%d%d",&N,&k);
for(int i=0;i<N;i++) scanf("%d%d",&a[i].first,&a[i].second);
priority_queue<P,vector<P>,cmp> pq;
int i=0;
for(;i<N&&i<k;i++) pq.push({a[i].first,a[i].second,i});
vector<int> ans;
for(;i<N;i++){
auto [id,t,pos] = pq.top();
vector<int> rp;
while(!pq.empty() && pq.top().t==t){
rp.push_back(pq.top().pos);
ans.push_back(pq.top().id);
pq.pop();
}
reverse(rp.begin(),rp.end());
for(auto r : rp){
pq.push({a[i].first,t+a[i].second,r});
i++;
if(i>=N) break;
}
i--;
}
while(!pq.empty()){
auto [id,t,pos] = pq.top(); pq.pop();
ans.push_back(id);
}
long long total=0;
for(int i=1;i<=N;i++) total+=i*(long long)ans[i-1];
printf("%lld",total);
}
[풀이] 가로 선분들과 세로 선분들을 나눠서 생각해보면 결국 가로 선분이 최대 몇개 겹칠 수 있는지, 세로 선분이 최대 몇개 겹칠 수 있는지를 각각 구해서 둘중 최댓값을 정답으로 출력하는 문제입니다. 번갈아 가면서 입력되는 가로 선분과 세로 선분을 각각 vector에 저장해줍니다. a[i%2].push_back({l,1}); a[i%2].push_back({r,-1}); 위와 같이 이런 스위핑 문제를 풀때 자주 사용하는 누적합 개념을 이용합니다. 선분이 시작되는 점에서 1을 더해주고 선분이 끝나는 점에서 1을 빼주면 어느 점에서 최대로 겹치는지 확인이 가능합니다.
[풀이] 모든 주민의 이름을 서로 XOR 계산을 하게 되면 O(N^2)의 시간복잡도로 시간초과가 발생하게 됩니다.
잘 생각해보면 각 XOR 계산의 결과가 얼마인지는 알 필요가 없고 총 합만 구하면 되기 때문에, 각 자리수끼리의 XOR 연산에서 총 얼마의 친밀도가 발생하는지 계산해서 답에 더해주면 됩니다. 예를 들어,
1001 0110 1000
위와 같이 세가지 수가 있을 때, 제일 좌측 4번째 자릿수의 값은 각각 1 0 1
입니다. 여기서 1이 2개, 0이 1개이기 때문에 서로간의 XOR 연산에서 2x1=2 가 생김을 알 수 있습니다. 이 숫자에 자릿수 2^3을 곱해주면 2 x (2^3) 이 되는데 이 값을 답에 더해주면 4번째 자릿수에서 발생하는 숫자의 계산은 끝이 납니다.
이렇게 모든 자릿수에 대해서 위와 같이 1과 0이 몇개 있는지를 체크해서 답에 더해주면 됩니다.
#include <cstdio>
int N;
long long onecnt[20];
int main(){
scanf("%d",&N);
for(int i=0;i<N;i++) {
int v;
scanf("%d",&v);
int j=0;
while(1){
if(v/2==0) {
onecnt[j]++;
break;
}
onecnt[j++]+=v%2;
v/=2;
}
}
long long ans=0;
for(int i=0;i<20;i++) ans+=(1<<i)*(N-onecnt[i])*onecnt[i];
printf("%lld",ans);
}