wxy 4.9 牛客训练赛50重现
v>
wxy 4.9 牛客训练赛50重现
5220
A
给一个字符串,如果相同的字母都连在一起,那么就是令人心情愉悦。如果前面和现在是同一个字母,
那么就更新该字母的位置,如果前面不是该字母但是该字母的,f数组之前更新过,那么就说明这个字母
不只一段。
题解从总长度入手。
B
模拟hash散列表的操作过程,采用记忆化搜索,r[x mod n ]记录原本应该在x mod n上的现如今应该在
哪里,也就是该段至今延申最右边是什么地方。
再次理解记忆化搜索,实质是以搜索实现的dp,一定要将搜过的记入下来,而且只考虑当前状态由什么
状态转移而来,不考虑子状态如何得来
# include <bits/stdc++.h>
using namespace std;
const int MAXN=1e6+100;
int a[MAXN],r[MAXN],ans[MAXN];
int n;
int dfs(int id)
{
if(r[id]==-1){
r[id]=id;
return id;
}
r[id]=dfs((r[id]+1)%n);
return r[id];
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d",&a[i]);
r[i]=-1,ans[i]=-1;
}
for(int i=0;i<n;++i){
int id=a[i]%n;
if(ans[id]==-1){
ans[id]=a[i];
r[id]=id;
}else{
int idd=dfs(id);
ans[idd]=a[i];
}
}
for(int i=0;i<n;++i){
printf("%d ",ans[i]);
}题解做法,并查集,将x mod n 放在同一个集合中,在x位置插入后,合并x和(x+1)%n,把后者作为祖先
C
写贪心写了一个小时,然后因为一个,一直过不了,然后改成三分写法,顺利卡过,三分牛逼。。。不
过r和l的差距放到400,可能如果数据再强一点就过不了了
return 0;
}
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e5+100;
struct Node{
int v,s;
}node[MAXN];
int cmp(Node a,Node b)
{
if(a.v==b.v) return a.s>b.s;
return a.v>b.v;
}
int n;
LL cal(int mid)
{
int now=0;
LL cans=0;
for(int i=1;i<=n;++i){
if(now>=mid) break;
if(node[i].s>=mid) ++now,cans+=node[i].v;
}
return cans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%d%d",&node[i].v,&node[i].s);
}
sort(node+1,node+n+1,cmp);
int l=0,r=n,lmid,rmid;
while(r-l>400){
lmid=(l+r)>>1,rmid=(r+lmid)>>1;
if(cal(lmid)<cal(rmid)) l=lmid;
else r=rmid;
}
LL ans=0;
for(int i=l;i<=r;++i){
ans=max(ans,cal(i));
}
printf("%lld\n",ans);
return 0;
}题解做法,首先按照siz排序,应为一堆中之取决于siz最低的那一个,然后如果当前队列中的比当前要
求的siz大,那么就把小的pop出来,每次都比较取最大即可
D
在某一点可以选择改变以后所有的边的权重,对i来说,只能在 i到n范围内选一个点修改,则正着用a跑
一遍dij,反着用b跑一遍dij,对于ans[i]来捉他可能时ans[i-1 ]还可能是d[i]+d1[i],采用堆优化的dij,否则会
T
想清楚复杂度用那一个板子和存图方式,然后还是不熟练,一改在半个小时内改出来,虽然C耽搁了很
久没在比赛时写出来,赛后也写了一个小时左右。
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
const int MAXN=1e5+100;
PII a[MAXN];
priority_queue<int,vector<int>,greater<int> > q;
int main()
{
int n; scanf("%d",&n);
for(int i=0;i<n;++i){
scanf("%d%d",&a[i].second,&a[i].first);
}
sort(a,a+n,greater<PII>());
LL ans=0,sum=0;
for(int i=0;i<n;++i){
q.push(a[i].second); sum+=a[i].second;
while(q.size()>a[i].first){
sum-=q.top();
q.pop();
}
ans=max(ans,sum);
}
printf("%lld\n",ans);
return 0;
}
# include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<LL,int> P;
const int MAXN=2e5+100;
const LL INF=0x3f3f3f3f3f3f3f3f;
int n,m,s,t;
struct Node{
int u,v;
LL a,b;
}node[MAXN];
LL ans[MAXN];struct Edge{
int u,v;
LL d;
Edge(int uu,int vv,LL dd):u(uu),v(vv),d(dd){}
};
vector<Edge> edges;
vector<int> G[MAXN];
int done[MAXN];
LL d[MAXN];
void add(int u,int v,LL w)
{
edges.push_back(Edge(u,v,w));
int mm=edges.size();
G[u].push_back(mm-1);
}
void dij()
{
priority_queue<P,vector<P>,greater<P> >Q;
for(int i=1;i<=n;i++) d[i]=INF;
d[s]=0;
memset(done,0,sizeof(done));
Q.push(P(0,s));
while(!Q.empty()){
P x=Q.top(); Q.pop();
int u=x.second;
if(done[u]) continue;
done[u]=1;
for(int i=0;i<G[u].size();i++){
Edge &e=edges[G[u][i]];
if(!done[e.v]&&d[e.v]>d[u]+e.d){
d[e.v]=d[u]+e.d;
Q.push(P(d[e.v],e.v));
}
}
}
}
void solve()
{
for(int i=0;i<m;i++){
Node no=node[i];
add(no.u,no.v,no.a);
add(no.v,no.u,no.a);
}
dij();
}
vector<Edge> edges1;
vector<int> G1[MAXN];
int done1[MAXN];
LL d1[MAXN];
void add1(int u,int v,LL w)
{
edges1.push_back(Edge(u,v,w));
int mm=edges1.size();
G1[u].push_back(mm-1);
}
void dij1()
{
priority_queue<P,vector<P>,greater<P> >Q1;E
给一个字符串,若子串作为一个十进制数能够被3整除且没有前导零则可以切割
O(n^2)的算法
for(int i=1;i<=n;i++) d1[i]=INF;
d1[s]=0;
memset(done1,0,sizeof(done1));
Q1.push(P(0,s));
while(!Q1.empty()){
P x=Q1.top(); Q1.pop();
int u=x.second;
if(done1[u]) continue;
done1[u]=1;
for(int i=0;i<G1[u].size();i++){
Edge &e=edges1[G1[u][i]];
if(!done1[e.v]&&d1[e.v]>d1[u]+e.d){
d1[e.v]=d1[u]+e.d;
Q1.push(P(d1[e.v],e.v));
}
}
}
}
void solve1()
{
swap(s,t);
for(int i=0;i<m;i++){
Node no=node[i];
add1(no.u,no.v,no.b);
add1(no.v,no.u,no.b);
}
dij1();
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;++i){
Node &no=node[i];
scanf("%d%d%lld%lld",&no.u,&no.v,&no.a,&no.b);
}
scanf("%d%d",&s,&t);
solve();
solve1();
for(int i=n;i;i--){
LL now=d[i]+d1[i];
if(i!=n) ans[i]=min(ans[i+1],now);
else ans[i]=now;
}
for(int i=1;i<=n;++i){
printf("%lld\n",ans[i]);
}
return 0;
}如何压复杂度:搞一个前缀和,把i之前所有符合条件的dp都加起来
所以由如上优化,cnt表示当前字符串前缀和,如果当前为0,那么dp[i]=ans之前拿到所有和,如果当
前为s[i]=='0'那么不能在i之前切割,说明dp[i-1]不包括在后面的数的前缀和中减去,ans加上当前的dp[]
值,并不区分只要当前和能整除3,就当作可以切割的,如果后面的为0,则在下一个把前面多加的减
去。
F
NTT待补
还是要多练,不管是心态或者是快速写出解法的能力,放平心态。
向wjmzbmr学习,acm本就是逆天而行。
浙公网安备 33010602011771号