简单模拟选做 & C++特性
海港
重点在于想到我们不关心每个人是第几批次,不关心同一时间同一国籍有几个人,所以可以只储存去重后的每个人的国籍和时间信息。
使用queue和map和pair,stl就是好用(
#include<iostream>
#include<cstdio>
#include<queue>
#include<map>
using namespace std;
const int N=200000;
int n,t[N];
queue<pair<int,int>>q,p;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
int k;scanf("%d%d",&t[i],&k);
map<int,int>m;
for(int j=1;j<=k;++j){
int x;scanf("%d",&x);
if(m[x]) continue;
m[x]=1;
q.push(make_pair(t[i],x));
}
}
map<int,int>m1;
for(int i=1;i<=n;++i){
while(p.front().first<=t[i]-86400&&!p.empty()){
if(--m1[p.front().second]==0) m1.erase(p.front().second);
p.pop();
}
while(q.front().first<=t[i]&&!q.empty()){
++m1[q.front().second];
p.push(q.front());q.pop();
}
printf("%d\n",m1.size());
}
return 0;
}
Home
题意:给定序列\(a_n\)和常数\(p\),求
\[\Sigma^{n}_{i=1}(2|x-a_i|+px)
\]
的最小值
解法:三分法求单峰函数极值,略卡常
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
const int N=1000010;
int n,p;
int a[N];
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9')
x=x*10+ch-'0',ch=getchar();
return x*f;
}
inline ll cal(ll x){
ll ans=p*x;
for(int i=1;i<=n;++i){
ans+=abs(a[i]-x)*2;
}
return ans;
}
inline int tri(int l,int r){
if(l==r) return l;
if(r-l==1){
ll cl=cal(l),cr=cal(r);
if(cl<=cr) return l;
return r;
}
if(r-l==2){
ll c1=cal(l),c2=cal((l+r)/2),c3=cal(r);
if(c1<=c2&&c1<=c3) return l;
if(c2<=c3) return (l+r)/2;
return r;
}
int m1=l+(r-l)/3,m2=r-(r-l)/3;
ll c1=cal(m1),c2=cal(m2);
if(c1>c2) return tri(m1,r);
return tri(l,m2);
}
int main(){
int T;T=read();while(T--){
// scanf("%d%d",&n,&p);
n=read();p=read();
int l=N,r=-N;
for(int i=1;i<=n;++i){
// scanf("%d",&a[i]);
a[i]=read();
l=min(l,a[i]);r=max(r,a[i]);
}
if(abs(p)>n*2) {printf("No\n");continue;}
if(abs(p)==n*2&&p>0) {printf("No\n");continue;}
int ans=tri(l,r);
printf("%d\n",ans);
}
return 0;
}
计算器的改良
注意一点细节:a+2a=4这个式子a默认系数是1;-2x=0解出来会x=-0.000,需要特判。。。
#define eps 0.000006
int main(){
char n,x;int a=0,b=0,c=0,d=0,flag=0,tmp=0,minus=1;double ans;
while(n=getchar()){
if(n>='0'&&n<='9') tmp=tmp*10+n-'0';
else{
tmp*=minus;
if(n>='a'&&n<='z'){
x=n;
if(tmp==0) tmp=1;
if(flag) c+=tmp;
else a+=tmp;
}else{
if(flag) d+=tmp;
else b+=tmp;
}tmp=0;minus=1;
if(n=='=') flag=1;
if(n=='-') minus=-1;
}
if(n=='\n') break;
} ans=1.0*(d-b)/(a-c);
if(fabs(ans)<eps) ans=0.0;
printf("%c=%.3lf",x,ans);
return 0;
}
跳房子
二分答案,需要维护RMQ,强制在线
维护RMQ有很多方法,最简单的ST表、单调队列、线段树,还有比较高级的FourRussian和笛卡尔树。这里ST表会爆空间(\(O(n^2)\))
因此使用deque实现单调队列维护RMQ,每次判断复杂度为线性,总复杂度\(O(nlogX)\)
不知道有没有什么更优雅的方法可以给f数组赋初始值,0x3f到底是什么原理?
感觉我的代码重构能力有待提升,不过最好还是 think twice code once 吧
这道题是NOIP2017普及组T4,也是我第一年参加普及组,没想到现在才补完题w
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int inf=1000000000;
int n,d,k,maxx,b_;
int x[1000000],s[1000000];
ll f[1000000];
deque<int> q;
bool solve(int g){
q.clear();memset(f,-0x3f,sizeof(f));f[0]=0;q.push_back(0);
int now=1;
for(int i=1;i<=n;++i){
int l=max(0,x[i]-(d+g)),r=min(x[i]-1,x[i]-(d-g));
if(r<0) continue;
while(!q.empty()&&x[q.front()]<l) q.pop_front();
while(x[now]<=r){
while(x[now]<l) ++now;
while(!q.empty()&&f[q.back()]<=f[now]) q.pop_back();
q.push_back(now);++now;
}
if(!q.empty()) f[i]=f[q.front()]+s[i];
if(f[i]>=k) return b_=1;
}
return 0;
}
int main(){
cin>>n>>d>>k;
for(int i=1;i<=n;++i) {cin>>x[i]>>s[i];maxx=max(maxx,x[i]);}
int l=0,r=maxx;while(l<=r){
int mid=(l+r)/2;
if(solve(mid)) r=mid-1;
else l=mid+1;
}
if(b_) cout<<l<<endl;
else cout<<-1<<endl;
return 0;
}
求和
这个求和公式 \((x+z)*(number_x+number_z)\) 果然是暗藏玄机
首先注意到三元组的分数与中间项无关,考虑分奇偶分别处理首尾项。把每种颜色单独提取出来,两两加和计算贡献,复杂度 \(O(n^2)\)
考虑优化:
\[
\sum x_i\sum num_i\newline
=(n-1)\sum{x_inum_i}+\sum_{i\ne j}{x_i num_j}\newline
=(n-2)\sum{x_inum_i}+\sum{x_i}\sum{num_i}
\]
单独验证一下 n=1 和 n=2 符合,这样可以优化到\(O(nlogn)\) ,log是我用优先队列筛选颜色整出来的,也可以用空间换时间优化到 \(O(n)\)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=200000,mod=10007;
int n,m,ans;
struct node{
int x,num,clr;
bool operator <(const node &temp)const{
return clr<temp.clr;
}
};
priority_queue<node>q0,q1;
int tmp1[N],tmp2[N];
signed main(){
cin>>n>>m;
for(int i=1;i<=n;++i) cin>>tmp1[i];
for(int i=1;i<=n;++i) cin>>tmp2[i];
for(int i=1;i<=n;++i){
node tmp={i,tmp1[i],tmp2[i]};
if(i%2) q1.push(tmp);
else q0.push(tmp);
}
while(!q0.empty()){
node now=q0.top();q0.pop();
if(q0.empty()) break;
int sum=now.x*now.num,sumx=now.x,sumn=now.num,cnt=1;
while(q0.top().clr==now.clr){
node t=q0.top();q0.pop();
sum+=t.x*t.num;sumx+=t.x;sumn+=t.num;
++cnt;
if(q0.empty()) break;
}
ans=(ans+(cnt-2)*sum+sumx*sumn)%mod;
}
while(!q1.empty()){
node now=q1.top();q1.pop();
if(q1.empty()) break;
int sum=now.x*now.num,sumx=now.x,sumn=now.num,cnt=1;
while(q1.top().clr==now.clr){
node t=q1.top();q1.pop();
sum+=t.x*t.num;sumx+=t.x;sumn+=t.num;
++cnt;
if(q1.empty()) break;
}
ans=(ans+(cnt-2)*sum+sumx*sumn)%mod;
}
cout<<ans<<endl;
return 0;
}
求交集
#include<iostream>
#include<cstdio>
#include<vector>
#include<sstream>
#include<algorithm>
#include<set>
using namespace std;
int main(){
string A, B, tmp;
getline(cin, A);getline(cin, B);
istringstream Astream(A), Bstream(B);
vector<int> a, b, c;
while(getline(Astream, tmp, ',')) a.push_back(stoi(tmp));
while(getline(Bstream, tmp, ',')) b.push_back(stoi(tmp));
for(int i = 0; i < a.size(); ++i){
for(int j = 0; j < b.size(); ++j){
if(a[i] == b[j]) c.push_back(a[i]);
}
}
if(c.empty()) cout<<"NULL"<<endl;
else{
sort(c.begin(), c.end());
cout<<c[0];
for(int i = 1; i < c.size(); ++i)
if(c[i]!=c[i-1])
cout<<','<<c[i];
}
}
根据日期求星期:
ctime库
#include <iostream>
#include <ctime>
#include <cstring>
using namespace std;
const string week[8] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
bool f(string x, string y){
int lenx = x.length(), leny = y.length();
for(int i = 0; i + leny <= lenx; ++i){
if(x.substr(i, leny) == y) return 1;
}
return 0;
}
int getMonth(string x){
if(f(x, "Jan")) return 1;
if(f(x, "Feb")) return 2;
if(f(x, "Mar")) return 3;
if(f(x, "Apr")) return 4;
if(f(x, "May")) return 5;
if(f(x, "Jun")) return 6;
if(f(x, "Jul")) return 7;
if(f(x, "Aug")) return 8;
if(f(x, "Sep")) return 9;
if(f(x, "Oct")) return 10;
if(f(x, "Nov")) return 11;
if(f(x, "Dec")) return 12;
return -1;
}
int getYear(string x){
int a[3], cnt = 0;
for(int i = 0; i < x.length(); ++i)
if(x[i] == '-') a[++cnt] = i;
if(a[1] == 4) return stoi(x.substr(0, 4));
if(a[2] == 6) return stoi(x.substr(7, 4));
return stoi(x.substr(a[1]+1, 4));
}
int getDay(string x){
int a[3], cnt = 0;
for(int i = 0; i < x.length(); ++i)
if(x[i] == '-') a[++cnt] = i;
if(a[1] == 2) return stoi(x.substr(0, 2));
if(a[2] == 8) return stoi(x.substr(9, 2));
return stoi(x.substr(a[1]+1, 2));
}
int main() {
int T;cin>>T;
while(T--){
string a;cin>>a;
int mon = getMonth(a),
day = getDay(a),
year = getYear(a);
// cout<<mon<<' '<<day<<' '<<year<<endl;
struct tm date = {};
date.tm_year = year - 1900;
date.tm_mon = mon - 1;
date.tm_mday = day;
time_t t = mktime(&date);
tm* localTime = localtime(&t);
cout<<week[localTime->tm_wday]<<'.'<<endl;
}
return 0;
}
好人坏人
约瑟夫,但是不需要考虑具体的位置,只需要考虑是否位于前k个即可
#include <iostream>
#include <cstdio>
using namespace std;
int solve(int k, int m) {
int cur = 0, now = k * 2;
while(now > k){
cur = (cur - 1 + m) % now;
if(cur < k) return 0;
--now;
}return 1;
}
int main() {
int k; cin >> k;
while (k) {
for (int i = 2; ; ++i) {
if (solve(k, i)) {
cout << i << endl;
break;
}
}
cin >> k;
}
return 0;
}
[ZJOI2008]泡泡堂
双指针对田忌和齐威王的马进行比较,每次贪心选择看起来最好的方案。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n, a[200000], b[200000];
bool cmp(int x, int y){
return x > y;
}
int f(int* a, int* b){
int la = 1, ra = n, lb = 1, rb = n, ans = 0;
for(int i = 1; i <= n; ++i){
if(a[la] > b[lb]){
++la;++lb;++ans;
}else if(a[la] < b[lb]){
--ra;++lb;--ans;
}else{
if(a[ra] < b[rb]){
--ra;++lb;--ans;
}else if(a[ra] > b[rb]){
--ra;--rb;++ans;
}else{
if(a[ra] < b[lb]){
--ans;
}
--ra;++lb;
}
}
}
return ans + n;
}
int main(){
// while(1){
cin>>n;
// if(n == 0) break;
for(int i = 1; i <= n; ++i) cin>>a[i]; //Tianji
for(int i = 1; i <= n; ++i) cin>>b[i]; //Qiweiwang
sort(a + 1, a + n + 1, cmp);sort(b + 1, b + n + 1, cmp);
cout<<f(a, b)<<' '<<n * 2 - f(b, a)<<endl;
// }
return 0;
}