A 图书管理
之前考过。。。
但是我忘了咋写了,然后随便胡了个动态开点权值数上去,\(O(n^2\log n)\) 拿了 \(80\)。。。
维护一个桶,检测到进来的两个数在中位数同侧,则中位数移动,否则不移动,然后就好了?。。。
点击查看代码
#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 两棵树
连通块数 = 剩余的点数 − 剩余的边数
贡献被拆成四个部分:点 × 点 − 边 × 点 − 点 × 边 + 边 × 边
这里以 边 × 边 为例,对于树 \(T\) 的边 \((u,v)\) 假设它被保留(概率 \(\frac 1 4\))
则树 \(U\) 中 \(u,v\) 必定被删除
计算树 \(u\) 中有多少边 \((x,y)\) 不以 \(u\) 或 \(v\) 为端点
每条边 \((x,y)\) 都有 \(\frac 1 4\) 概率被保留
用 set 维护每个点的边,时间复杂度 \(O(n\log n)\)
点击查看代码
#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)
实际上 \(O(n^2)\) 可以过百万。。。
然后有一个优化可以直接干过标算,就是我们知道异或有一个性质是 \(A\text{ xor }B\text{ xor }A=B\),那我们可以开 \(map\) 存每个 \(x_i\),然后枚举 \(j=a\text{ xor }x\),找到 \(j\in{[0,B]}\) 的所有,去反过来找 \(j\text{ xor }a=x\) 在 \(map\) 里面有没有,如果有,那看它的上一位或者下一位有没有大于 \(B\) 的,因为这样找到的 \(j\) 一定小于 \(B\),那两个函数就是异号,乘起来小于等于 \(0\)。
否则如果 \(B>n\),直接跑暴力得了,因为枚举次数小于 \(B\) 的。
然后就过了,如果手写哈希表能更快。
点击查看代码
#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
\(O(n^2)\) 枚举所有情况。
60pts
通过整体二分,判定 \([1,mid]\) 内是否有解的方式找到第一组解,或利用离线数据结构技巧进行求解,复杂度为 \(O(n \log n \log C)\),与正解关联性不大。
100pts
求解 \(x_i \oplus a\) 最小和最大的两个位置 \(c_1,c_2\),如果 \(f(c_1) \times f(c_2) > 0\) 显然无解。
否则每次取 \(c_1,c_2\) 中点 \(mid\),因为 \(f(c_1),f(c_2)\) 异号,所以 \(f(c_1),f(mid)\) 和 \(f(mid),f(c_2)\) 必然有一对异号,每次区间长度减半,因此重复 \(\log\) 次即可。
求解 \(x_i \oplus a\) 最小和最大的两个位置 \(c_1,c_2\) 可以利用 trie 快速求解,时间复杂度为 \(((n+q) (\log n + \log V))\)。
D 编辑(edit.cpp)
全输出零有 60,望周知。
30pts
枚举 \(T\) 的某一子串进行编辑距离求解的DP,具体状态为让 \(A\) 变成 \(B\),现在只考虑 \(A[1:i]\) 变成 \(B[1:j]\) 的编辑距离为 \(f[i][j]\),转移时考虑删除,添加,修改第 \(i+1\) 个位置即可,时间复杂度为 \(O(n^4)\)。
100pts
枚举每个后缀,\(f_{i,j}\) 表示最大的 \(x\),使得 \(S[1:x]\) 和 \(T[1:x+j]\) 可以在 \(i\) 次编辑内得到,显然若 \(x\) 可以,所有\(x_0 \leq x\), \(S[1:x_0]\) 和 \(T[1:x_0+j]\) 都可以在 \(i\) 次编辑内得到。
考虑如何转移,先考虑做完第 \(j\) 次编辑操作后往外延申,可以延申的即为 \(S\) 的一个后缀和 \(T\) 的一个后缀的最长公共前缀,即\(f_{i,j} = f_{i,j} + \text{LCP}(S[f_{i,j + 1}:|S|],T [f_{i,j} + j + 1 . .: |T|])\),随后我们可以通过对\(f_{i+1,j-1},f_{i+1,j},f_{i+1,j+1}\) 三项进行转移,即考虑下一次的编辑的具体操作是删除添加还是修改。
每次要算的两个后缀的前缀下标不会差超过 \(k\),因此一共至多求 \(O(nk)\) 次 LCP,可以利用二分+ hash 的方式解决。
记录每个后缀中 \(f_{i,j}=|S|\) 的那些状态,即可计算出最终答案,时间复杂度为 \(O(nk^2+nk \log n)\)。
标签:log,noip,int,freopen,ans,now,模拟,Mod From: https://www.cnblogs.com/ccjjxx/p/18533001