简单模拟选做 & 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
题意:给定序列
的最小值
解法:三分法求单峰函数极值,略卡常
#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表会爆空间(
因此使用deque实现单调队列维护RMQ,每次判断复杂度为线性,总复杂度
不知道有没有什么更优雅的方法可以给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; }
求和
这个求和公式
首先注意到三元组的分数与中间项无关,考虑分奇偶分别处理首尾项。把每种颜色单独提取出来,两两加和计算贡献,复杂度
考虑优化:
单独验证一下 n=1 和 n=2 符合,这样可以优化到
#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; }
四则运算表达式的值
处理了左括号右边是正负号和等式开头是正负号的情况,并且把中缀转后缀和后缀表达式求值合并到一起进行。
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <stack> using namespace std; int judge(char ch){ if(ch == '+' || ch == '-') return 1; if(ch == '*' || ch == '/') return 2; if(ch == '(' || ch == ')') return 0; if(ch >= '0' && ch <= '9') return -1; return -2; } int suf(string str){ string ans; stack<int> nums; stack<char> opers; if(judge(str[0]) > 0) nums.push(0); for(int i = 0; i < str.length(); ++i){ int typ = judge(str[i]); if(typ == -1){ string tmp;tmp += str[i]; while(judge(str[i + 1]) == -1) tmp += str[++i]; nums.push(stoi(tmp)); }else if(typ > 0){ if(opers.empty() || judge(opers.top()) < typ){ opers.push(str[i]); }else{ while(!opers.empty() && judge(opers.top()) >= typ){ char oper = opers.top();opers.pop(); int y = nums.top();nums.pop(); int x = nums.top();nums.pop(); if(oper == '+') nums.push(x + y); if(oper == '-') nums.push(x - y); if(oper == '*') nums.push(x * y); if(oper == '/') nums.push(x / y); } opers.push(str[i]); } }else if(str[i] == '('){ if(judge(str[i + 1]) > 0) nums.push(0); opers.push('('); }else if(str[i] == ')'){ char oper = opers.top();opers.pop(); while(oper != '('){ int y = nums.top();nums.pop(); int x = nums.top();nums.pop(); if(oper == '+') nums.push(x + y); if(oper == '-') nums.push(x - y); if(oper == '*') nums.push(x * y); if(oper == '/') nums.push(x / y); oper = opers.top();opers.pop(); } } } while(!opers.empty()){ char oper = opers.top();opers.pop(); int y = nums.top();nums.pop(); int x = nums.top();nums.pop(); if(oper == '+') nums.push(x + y); if(oper == '-') nums.push(x - y); if(oper == '*') nums.push(x * y); if(oper == '/') nums.push(x / y); } return nums.top(); } int main() { string str; while(cin>>str) cout<<suf(str)<<endl; return 0; }
愉悦的假期(USACO11NOV)
分两种情况,一种是三个块两两连接,一种是一个点直接连三个块。
第一种情况
#include <iostream> #include <queue> #include <utility> #include <vector> #include <map> #include <cstring> using namespace std; //const int inf = 1e9; const int N = 51; int n, m, cnt = 0, maxx = 0; char mp[N][N]; int fax[N][N], fay[N][N]; int ans[N][N][N][N]; int dx[4] = {0, 0, -1, 1}; int dy[4] = {-1, 1, 0, 0}; void dfs(int x, int y, int fx, int fy){ fax[x][y] = fx;fay[x][y] = fy; for(int i = 0; i < 4; ++i){ int nx = x + dx[i], ny = y + dy[i]; if(mp[nx][ny] == 'X' && (fax[nx][ny] == 0 && fay[nx][ny] == 0)) dfs(nx, ny, fx, fy); } } int main() { cin>>n>>m; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) cin>>mp[i][j]; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j){ if(mp[i][j] == '.') continue; if(fax[i][j] && fay[i][j]) continue; dfs(i, j, i, j); } for(int x1 = 1; x1 <= n; ++x1) for(int y1 = 1; y1 <= m; ++y1){ if(mp[x1][y1] == '.') continue; for(int x2 = 1; x2 <= n; ++x2) for(int y2 = 1; y2 <= m; ++y2){ if(mp[x2][y2] == '.') continue; if(fax[x1][y1] == fax[x2][y2] && fay[x1][y1] == fay[x2][y2]) continue; int fx1 = fax[x1][y1], fy1 = fay[x1][y1], fx2 = fax[x2][y2], fy2 = fay[x2][y2]; if(ans[fx1][fy1][fx2][fy2] == 0) ans[fx1][fy1][fx2][fy2] = abs(x1-x2)+abs(y1-y2)-1; else ans[fx1][fy1][fx2][fy2] = ans[fx2][fy2][fx1][fy1] = min(ans[fx1][fy1][fx2][fy2], abs(x1-x2)+abs(y1-y2)-1); } } for(int x1 = 1; x1 <= n; ++x1) for(int y1 = 1; y1 <= m; ++y1) for(int x2 = 1; x2 <= n; ++x2) for(int y2 = 1; y2 <= m; ++y2) if(ans[x1][y1][x2][y2]){ if(x2 > x1 || (x2 == x1 && y2 > y1)) continue; cnt += ans[x1][y1][x2][y2]; maxx = max(maxx, ans[x1][y1][x2][y2]); } cnt -= maxx; int num = cnt; map<pair<int, int>, int> man; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j){ if(mp[i][j] == 'X') continue; man.clear(); for(int x = 1; x <= n; ++x) for(int y = 1; y <= m; ++y){ if(mp[x][y] == '.') continue; if(!man[make_pair(fax[x][y], fay[x][y])]) man[make_pair(fax[x][y], fay[x][y])] = abs(i-x)+abs(j-y); else man[make_pair(fax[x][y], fay[x][y])] = min(man[make_pair(fax[x][y], fay[x][y])], abs(i-x)+abs(j-y)); } int tmp = 0; for(auto m : man) tmp += m.second; num = min(num, tmp-2); // cout<<man.size()<<' '<<m<<endl; } cout<<num<<endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效