Comet OJ - Contest #14

Rank38。
还是比较不满意吧,C卡了太久,E没调出来,D也没空去做了。

A

签到题。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=100007;
int x[N],y[N];
ll sqr(ll x){return 1ll*x*x;}
ll dis(ll x,ll y,ll a,ll b){return sqr(x-a)+sqr(y-b);}
int main()
{
    ll ans=0,n,i,a,b,x,y,r;
    cin>>n>>a>>b>>r;
    for(i=1;i<=n;++i)
    {
    cin>>x>>y;
    if(dis(x,y,a,b)<=sqr(r)) ++ans;
    }
    cout<<ans;
}

B

计算\(p,i,n\)分别最前能放在哪里,\(i,n,k\)最后能放在哪里。

#include<bits/stdc++.h>
using namespace std;
vector<int>pos[5];
const int N=1000007;
char s[N];int n,mp[1001];
int Finda(int x)
{
    int p=0;
    for(int i=1;i<=x;++i)
    {
    auto it=lower_bound(pos[i].begin(),pos[i].end(),p);
    if(it==pos[i].end()) return -1;
    p=pos[i][it-pos[i].begin()];
    }
    return p;
}
int Findb(int x)
{
    int p=n+1;
    for(int i=4;i>=x;--i)
    {
    auto it=upper_bound(pos[i].begin(),pos[i].end(),p);
    if(it==pos[i].begin()) return -1;
    it=prev(it);
    p=pos[i][it-pos[i].begin()];
    }
    return p;
}
int main()
{
    int T,i;scanf("%d",&T);
    mp['p']=1,mp['i']=2,mp['n']=3,mp['k']=4;
    while(T--)
    {
    scanf("%d%s",&n,s+1);int f=0,flg=0;
    for(i=1;i<=4;++i) pos[i].clear();
    for(i=1;i<=n;++i) if(mp[s[i]]) pos[mp[s[i]]].push_back(i);
    for(i=1;i<=3;++i)
    {
        int p1=Finda(i);
        if(p1==-1) continue;
        int p2=Findb(i+1);
        if(p2==-1) continue;
        if(p2<p1) continue;
        f=max(f,p2-p1-1),flg=1;
    }
    if(!flg) puts("-1");
    else printf("%d\n",f);
    }
}

C

设\(f_i\)表示分界点为\(i\)的个数。
对于一次操作\((i,l,r)\)。
我们会在\(l-1,r\)将\(f\)加上\(2^{i-1}\)。
而\([1,l)\cup(r,n]\)这一部分不会变,所以\(f\)要\(*2\)。

#include<bits/stdc++.h>
using namespace std;
const int N=2007,P=20050321;
int a[N];
int read(){int x;scanf("%d",&x);return x;}
int inc(int a,int b){return a+=b,a>=P? a-P:a;}
int mul(int a,int b){return 1ll*a*b%P;}
int power(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int main()
{
    int n=read(),m=read(),i,l,r,x,ans;
    a[0]=1;
    for(i=1;i<=m;++i)
    {
    l=read(),r=read(),x=power(2,i-1),ans=0;
    for(int i=0;i<l-1;++i) a[i]=inc(a[i],a[i]);
    for(int i=r+1;i<n;++i) a[i]=inc(a[i],a[i]);
    a[l-1]=inc(a[l-1],x),a[r]=inc(a[r],x);
    for(int i=0;i<n;++i) ans=inc(ans,a[i]);
    cout<<ans<<endl;
    }
}

D

询问离线右端点升序排序。
用树状数组维护第\(x\)个操作的贡献。
查询就是简单的区间查询。
然后操作可以用珂朵莉树维护序列的极大连续子段,每次暴力修改同时维护树状数组。

#include<bits/stdc++.h>
#define ll long long
#define IT set<node>::iterator
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[19],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
    void write(ll x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');}
}
using namespace IO;
const int N=500007;
int n,m,Q;ll ans[N];
struct operation{int l,r,v;}opt[N];
struct query{int l,r,id;}q[N];
struct BIT
{
    ll t[N];
    void add(int p,ll v){if(!p)return;for(;p<=n;p+=p&-p)t[p]+=v;}
    ll ask(int p){ll s=0;for(;p;p^=p&-p)s+=t[p];return s;}
    ll query(int l,int r){return ask(r)-ask(l-1);}
}bit;
struct node{int l,r,x,id;node(int a=0,int b=0,int c=0,int d=0){l=a,r=b,x=c,id=d;}};
int operator<(node a,node b){return a.l<b.l;}
set<node>s;
IT split(int pos)
{
    IT it=s.lower_bound(node(pos));
    if(it!=s.end()&&it->l==pos) return it;
    --it;
    int L=it->l,R=it->r,X=it->x,ID=it->id;
    s.erase(it),s.insert(node(L,pos-1,X,ID));
    return s.insert(node(pos,R,X,ID)).first;
}
void assign(int l,int r,int x,int id)
{
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl,s.erase(prev(itl))) bit.add(itl->id,-1ll*((itl->r)-(itl->l)+1)*(itl->x));
    s.insert(node(l,r,x,id));
    bit.add(id,1ll*(r-l+1)*x);
}
int main()
{
    n=read(),m=read(),Q=read();int i,j=1;
    for(i=1;i<=n;++i) opt[i]={read(),read(),read()};
    for(i=1;i<=Q;++i) q[i]={read(),read(),i};
    sort(q+1,q+Q+1,[](query a,query b){return a.r<b.r;}),s.insert(node(1,m,0,0));
    for(i=1;i<=n;++i)
    {
    assign(opt[i].l,opt[i].r,opt[i].v,i);
    while(j<=Q&&q[j].r==i) ans[q[j].id]=bit.query(q[j].l,i),++j;
    }
    for(i=1;i<=Q;++i) write(ans[i]);
    return Flush(),0;
}

E

先tarjan,然后在DAG上dp。(tarjan的scc的编号反序就是拓扑序)
具体的维护一下从\(1\)到每个scc的最短边,最长边和最大路径边权极差即可。

#include<bits/stdc++.h>
#define pi pair<int,int>
#define fi first
#define se second
#define pb push_back
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using namespace IO;
int min(int a,int b){return a<b? a:b;}
int max(int a,int b){return a>b? a:b;}
const int N=200007,M=500007;
vector<pi>G[N],E[N];
struct edge{int u,v,w;}e[M];
struct node{int mn,mx,ans;node(int a=0,int b=0,int c=0){mn=a,mx=b,ans=c;}}f[N];
int n,m,Q,dfn[N],low[N],Time,stk[N],top,cnt,vis[N],bel[N],mx[N],mn[N];
node merge(node a,node b)
{
    a.ans=max(max(max(a.ans,b.ans),a.mx-b.mn),b.mx-a.mn);
    a.mx=max(a.mx,b.mx);
    a.mn=min(a.mn,b.mn);
    return a;
}
void tarjan(int u)
{
    dfn[u]=low[u]=++Time,stk[++top]=u,vis[u]=1;
    for(pi x:G[u])
    {
    int v=x.fi;
    if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]);
    else if(vis[v]) low[u]=min(low[u],dfn[v]);
    }
    if(dfn[u]==low[u])
    {
    ++cnt;
    while(stk[top+1]^u) bel[stk[top]]=cnt,vis[stk[top--]]=0;
    }
}
int main()
{
    n=read(),m=read(),Q=read(),memset(mn,0x3f,sizeof mn);
    for(int i=1,u,v,w;i<=m;++i) u=read(),v=read(),w=read(),e[i]=(edge){u,v,w},G[u].pb(pi(v,w));
    tarjan(1);
    for(int i=1;i<=n;++i) if(bel[i]) bel[i]=cnt+1-bel[i];
    for(int i=1,id;i<=m;++i)
    if(bel[e[i].u]&&bel[e[i].v])
        if(bel[e[i].u]==bel[e[i].v]) id=bel[e[i].u],mn[id]=min(mn[id],e[i].w),mx[id]=max(mx[id],e[i].w);
        else E[bel[e[i].v]].pb(pi(bel[e[i].u],e[i].w));
    for(int u=1;u<=cnt;++u)
    {
    node s=f[u]=node(mn[u],mx[u],mx[u]-mn[u]);
    for(pi x:E[u])
    {
        int v=x.fi,w=x.se;
        node t=merge(s,merge(node(w,w,0),f[v]));
        f[u]=node(min(f[u].mn,t.mn),max(f[u].mx,t.mx),max(f[u].ans,t.ans));
    }
    }
    for(int u;Q;--Q)
    {
    u=read();
    if(!bel[u]||f[bel[u]].ans<0) puts("-1");
    else printf("%d\n",f[bel[u]].ans);
    }
}

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/11824583.html

时间: 2024-10-08 17:00:39

Comet OJ - Contest #14的相关文章

Comet OJ - Contest #14题解

Contest14的本质:区间覆盖+Tarjan( A 把距离公式两边平方即可 注意要long long code #include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #define fo(a,b,c) for (a=b; a<=c; a++) #define fd(a,b,c) for (a=b;

符文能量(Comet OJ - Contest #8)

给Comet OJ打个小广告,挺好用的,比较简洁,给人感觉很好用 Contest #8是我打的第一场本oj比赛,很遗憾A了前两道傻逼题就没思路了,然后就不打算打了....... https://www.cometoj.com/contest/58/problem/C?problem_id=2760 怎么做啊完全不会啊我那么菜,虽然看到是dp但嫌太麻烦就放弃了: 靠后仔细想了想原来这道题很简单: 结构体node e[];储存ai,bi值(当然你用数组我也不拦着),因为合并的方式很特殊,可以不管合并

Comet OJ - Contest #5

Comet OJ - Contest #5 总有一天,我会拿掉给\(dyj\)的小裙子的. A 显然 \(ans = min(cnt_1/3,cnt_4/2,cnt5)\) B 我们可以感性理解一下,最大的满足条件的\(x\)不会太大 因为当\(x\)越来越大时\(f(x)\)的增长速度比\(x\)的增长速度慢得多 其实可以证明,最大的满足的\(x\)不会超过\(100\) 因为没有任何一个三位数的各位之和大于等于\(50\) 所以我们就直接预处理\(1-99\)所有的合法的 暴力枚举即可 其实

Comet OJ - Contest #10 B

Comet OJ - Contest #10 B 沉鱼落雁 思维题 题意 : 每个数字最多重复出现三次,有n给数字,让你尽可能的使得相同数字之间的最小距离尽可能大 思路 :分三种情况套路 设 a b c 分别代表出现 一次, 两次, 三次 数字的个数 所有元素至多出现一次,答案为 n,题目规定 所有元素至多出现两次, 例如 1 1 2,可以排列成 1 2 1,所以,答案为 1 例如 1 1 2 2 3,可以排列成 1 2 3 1 2,所有 答案为 2 思考后得出,应该尽可能的把 b 个出现两次的

Comet OJ - Contest #7 解题报告

传送门:https://www.cometoj.com/contest/52 A:签到题 题意:多次询问,每次询问给出一个值域区间[l,r],从这区间范围中选出两个整数(可重复),依次求出这俩数的“最大的最小公倍数”.“最小的最小公倍数”.“最大的最大公约数”.最小的最大公约数. 分析:(1)显然,当区间长度为1时,该问题的答案只能是区间中仅有的那个数. (2)当区间的长度大于1时,最大的最小公倍数,lcmmax =lcm(ar,ar-1) = ar * ar-1: 最小的最小公倍数,lcmmi

Comet OJ - Contest #15题解

A 双十一特惠 (简单版) n  <=  1e19,   1e9 > 1(8) https://www.cometoj.com/contest/79/problem/A?problem_id=4198 #include<bits/stdc++.h> using namespace std; int main(){ int t; cin >> t; while(t--) { int cnt1 = 0; int n;cin >> n; int pr[] = {1

Comet OJ - Contest #15

https://cometoj.com/contest/79/problem/D?problem_id=4219 题目描述 ※ 简单版与困难版的唯一区别是粗体字部份和 $v$ 的数据范围. 在双 11 时,心慧精品店有个特别的折价活动如下: 首先,我们定义一个正整数为"好的"当且仅当此数仅由数字 1 构成,举例来说 1, 11, 111, 11111 都是「好的」,但 10.123.321 都是「不好的」. 接着,若一个商品原价为 x,若顾客能把 x 表示为 k 个「好的」数字,那么此

Comet OJ - Contest #0

A:化成x-√n=y+z-√4yz的形式,则显然n是完全平方数时有无数组解,否则要求n=4yz,暴力枚举n的因数即可.注意判断根号下是否不小于0. #include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define ll long

Comet OJ - Contest #1

A:随便怎么暴力. #include<bits/stdc++.h> using namespace std; #define ll long long #define N 25 char getc(){char c=getchar();while (c!='.'&&c!='#') c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char