简单模拟选做 & 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;
}
posted @ 2024-03-22 18:26  hcx1999  阅读(7)  评论(0编辑  收藏  举报