noip模拟8
A 图书管理
之前考过。。。
但是我忘了咋写了,然后随便胡了个动态开点权值数上去, 拿了 。。。
维护一个桶,检测到进来的两个数在中位数同侧,则中位数移动,否则不移动,然后就好了?。。。
点击查看代码
#include<bits/stdc++.h> using namespace std; int n; const int N=1e4+4; int mx=1e4; int a[N]; bitset<N>vis; signed main() { freopen("book.in","r",stdin); freopen("book.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n;long long ans=0; for(int i=1;i<=n;i++)cin>>a[i],ans+=(1ll*i*i*a[i]); for(int i=1;i<=n;i++) { int now=a[i]; vis.reset(); vis[a[i]]=1; for(int j=i+2;j<=n;j+=2) { int a1=a[j-1],a2=a[j]; if(a1>a2)swap(a1,a2); vis[a1]=1,vis[a2]=1; if(a1<now&&a2>now); else if(a1<now&&a2<now) { --now; while(!vis[now])now--; } else if(a1>now&&a2>now) { ++now; while(!vis[now])now++; } ans+=(1ll*i*j*now); } } cout<<ans; return 0; }
哎呀我是真唐,这都忘了。。
B 两棵树
连通块数 = 剩余的点数 − 剩余的边数
贡献被拆成四个部分:点 × 点 − 边 × 点 − 点 × 边 + 边 × 边
这里以 边 × 边 为例,对于树 的边 假设它被保留(概率 )
则树 中 必定被删除
计算树 中有多少边 不以 或 为端点
每条边 都有 概率被保留
用 set 维护每个点的边,时间复杂度
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long const int mod=998244353; int Mod(int x) { if(x<0) { if(x<=-mod) x%=mod; if(x==0) return 0; return x+mod; } return x>=mod?x%mod:x; } const int inv2=499122177,inv4=748683265,inv8=873463809,inv16=935854081; const int maxn=2e5; set<pair<int,int> >se; int deg[maxn+5]; signed main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int n;cin>>n; int ans=Mod(Mod(n*Mod((n-1)*inv4))-Mod((n-2)*Mod((n-1)*inv4))); for(int i=1;i<n;i++) { int u,v;cin>>u>>v; if(u>v)swap(u,v); se.insert({u,v}); deg[u]++,deg[v]++; } for(int i=1;i<n;i++) { int u,v;cin>>u>>v; if(u>v)swap(u,v); ans=Mod(ans+Mod((n-1-deg[u]-deg[v]+se.count({u,v}))*inv16)); } cout<<ans; return 0; }
C 函数(fun)
实际上 可以过百万。。。
然后有一个优化可以直接干过标算,就是我们知道异或有一个性质是 ,那我们可以开 存每个 ,然后枚举 ,找到 的所有,去反过来找 在 里面有没有,如果有,那看它的上一位或者下一位有没有大于 的,因为这样找到的 一定小于 ,那两个函数就是异号,乘起来小于等于 。
否则如果 ,直接跑暴力得了,因为枚举次数小于 的。
然后就过了,如果手写哈希表能更快。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long int n,q; const int N=1e6+5; int x[N]; int a,b; inline int f(int i) { return (i^a)-b; } unordered_map<int,int>mp; signed main() { // freopen("C.in","r",stdin); // freopen("C1.out","w",stdout); freopen("fun.in","r",stdin); freopen("fun.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>q; for(int i=1;i<=n;i++) cin>>x[i],mp[x[i]]=i; while(q--) { cin>>a>>b; int ans=0; if(b>n) { for(int i=n-1;i>=1;i--) { if(f(x[i])*f(x[i+1])<=0){ans=i;break;} } } else { for(int i=b;i>=0;i--) { int now=mp[i^a]; if(!now)continue; if(now<n&&(x[now+1]^a)>=b) { ans=now;break; } if(now>1&&(x[now-1]^a)>=b) { ans=now-1;break; } } } ans=ans>0?ans:-1; cout<<ans<<"\n"; } return 0; }
正解是这样的:
30pts
枚举所有情况。
60pts
通过整体二分,判定 内是否有解的方式找到第一组解,或利用离线数据结构技巧进行求解,复杂度为 ,与正解关联性不大。
100pts
求解 最小和最大的两个位置 ,如果 显然无解。
否则每次取 中点 ,因为 异号,所以 和 必然有一对异号,每次区间长度减半,因此重复 次即可。
求解 最小和最大的两个位置 可以利用 trie 快速求解,时间复杂度为 。
D 编辑(edit.cpp)
全输出零有 60,望周知。
30pts
枚举 的某一子串进行编辑距离求解的DP,具体状态为让 变成 ,现在只考虑 变成 的编辑距离为 ,转移时考虑删除,添加,修改第 个位置即可,时间复杂度为 。
100pts
枚举每个后缀, 表示最大的 ,使得 和 可以在 次编辑内得到,显然若 可以,所有, 和 都可以在 次编辑内得到。
考虑如何转移,先考虑做完第 次编辑操作后往外延申,可以延申的即为 的一个后缀和 的一个后缀的最长公共前缀,即,随后我们可以通过对 三项进行转移,即考虑下一次的编辑的具体操作是删除添加还是修改。
每次要算的两个后缀的前缀下标不会差超过 ,因此一共至多求 次 LCP,可以利用二分+ hash 的方式解决。
记录每个后缀中 的那些状态,即可计算出最终答案,时间复杂度为 。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long #define ull unsigned long long const int N=5e4+5,M=35; const ull p=13331; int k,s1,t1,ans[M],f[M][M<<1]; ull pp[N],h1[N],h2[N]; char s[N],t[N]; inline ull gt1(int l,int r) { return h1[r]-h1[l-1]*pp[r-l+1]; } inline ull gt2(int l,int r) { return h2[r]-h2[l-1]*pp[r-l+1]; } bool ck(int lx,int rx,int ly,int ry) { return gt1(lx,rx)==gt2(ly,ry); } int getlcp(int x,int y) { int l=1,r=min(s1-x+1,t1-y+1),mid; while(l<=r) { mid=(l+r)>>1; if(ck(x,x+mid-1,y,y+mid-1)) l=mid+1; else r=mid-1; } return l-1; } void solve(int l) { for(int i=0;i<=k;i++) for(int j=0;j<=2*30;j++) f[i][j]=-1; f[0][30]=0; for(int i=0;i<=k;i++) { for(int j=-i;j<=i;j++) { if(f[i][30+j]==-1)continue; f[i][30+j]=f[i][30+j]+getlcp(f[i][30+j]+1,l-1+f[i][30+j]+j+1); f[i+1][30+j-1]=max(f[i+1][30+j-1],f[i][30+j]+1); f[i+1][30+j]=max(f[i+1][30+j],f[i][30+j]+1); f[i+1][30+j+1]=max(f[i+1][30+j+1],f[i][30+j]); } } for(int j=-k;j<=k;j++) { for(int i=0;i<=k;i++) { if(s1+j>=1&&s1+j<=t1-l+1&&f[i][30+j]>=s1) { ++ans[i];break; } } } } signed main() { freopen("edit.in","r",stdin); freopen("edit.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>k; cin>>(s+1)>>(t+1); s1=strlen(s+1),t1=strlen(t+1); pp[0]=1; for(int i=1;i<=s1;i++) { h1[i]=h1[i-1]*p+s[i]-'a'; pp[i]=pp[i-1]*p; } for(int i=1;i<=t1;i++) { h2[i]=h2[i-1]*p+t[i]-'a'; pp[i]=pp[i-1]*p; } for(int i=1;i<=t1;i++) solve(i); for(int i=0;i<=k;i++) cout<<ans[i]<<"\n"; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战