2018-2019 ICPC, NEERC, Southern Subregional Contest

目录

  • 2018-2019 ICPC, NEERC, Southern Subregional Contest
    (Codeforces 1070)

    • A.Find a Number(BFS)
    • C.Cloud Computing(线段树)
    • D.Garbage Disposal(模拟)
    • E.Getting Deals Done(二分)
    • F.Debate(贪心)
    • H.BerOS File Suggestion(后缀自动机)
    • I.Privatization of Roads in Berland(网络流)

2018-2019 ICPC, NEERC, Southern Subregional Contest
(Codeforces 1070)

比赛链接

B题看不懂样例=-=其它题咕咕了。

A.Find a Number(BFS)

先要想到令\(f[i][j]\)表示模\(d\)余数为\(i\),数位和为\(j\)的最小数。状态数是OK的。
然后每次转移就是在后面加上\(0\sim 9\)这些数字,用BFS转移就可以保证当前数最小了。复杂度\(O(10ds)\)。
当然还有其它奇奇怪怪的DP方法。

//124ms 32100KB
#include <queue>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=503,M=5003;

bool vis[N][M];
struct Node
{
    int r,sum;
};
struct Path
{
    int r,sum;
    char c;
}pre[N][M];

void BFS(const int d,const int s)
{
    std::queue<Node> q;
    q.push((Node){0,0}), vis[0][0]=1;
    while(!q.empty())
    {
        Node x=q.front(); q.pop();
        if(!x.r && x.sum==s) return;
        for(int i=0; i<10; ++i)
        {
            int r=(x.r*10+i)%d, sum=x.sum+i;
            if(sum<=s && !vis[r][sum])
                pre[r][sum]=(Path){x.r,x.sum,char(i+48)}, vis[r][sum]=1, q.push((Node){r,sum});
        }
    }
}
void Output(int d,int s)
{
    if(pre[d][s].c) Output(pre[d][s].r,pre[d][s].sum), pc(pre[d][s].c);
}

int main()
{
    int d,s; scanf("%d%d",&d,&s);
    BFS(d,s);
    if(vis[0][s]) Output(0,s);
    else puts("-1");

    return 0;
}

C.Cloud Computing(线段树)

我写的比较无脑... 按天数为下标建线段树。将物品区间按价格排序,考虑依次加到线段树对应区间上。
设当前区间剩余所需个数的最小值是\(mn\)(初始都为\(k\)),当前物品区间、个数、单位价格分别是\((l,r,a,cost)\)。\(mn\gt a\)时,直接区间减\(a\)统计一下答案就行了;当\(mn\leq a\)时,一定至少有一个位置会被减成\(0\),暴力在线段树找到那个/那些位置把\(size\)清零,\(mn\)设为\(INF\),统计一下答案即可。
因为每个数只会被清空一次,也就是只会暴力做\(O(n)\)次,所以复杂度\(O((n+m)\log n)\)。
其实只要拿价格建一棵值域线段树,每个位置维护有多少个物品就行了。查询就是在树上二分出前\(k\)小的和(树状数组也行)。

//327ms 78600KB
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
#define MAXIN 500000
//#define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
typedef long long LL;
const int N=1e6+5;
const LL INF=3e18;

char IN[MAXIN],*SS=IN,*TT=IN;
struct Node
{
    int l,r,num,cost;
    bool operator <(const Node &x)const
    {
        return cost<x.cost;
    }
}A[N];
struct Segment_Tree
{
    #define ls rt<<1
    #define rs rt<<1|1
    #define lson l,m,ls
    #define rson m+1,r,rs
    #define S N<<2
    LL mn[S];//mn[rt]=INF要足够大!
    int sz[S],tag[S];
    LL Ans;
    #undef S
    #define Upd(rt,v) mn[rt]+=v, tag[rt]+=v
    #define Update(rt) mn[rt]=std::min(mn[ls],mn[rs]), sz[rt]=sz[ls]+sz[rs]
    inline void PushDown(int rt)
    {
        Upd(ls,tag[rt]), Upd(rs,tag[rt]), tag[rt]=0;
    }
    void Build(int l,int r,int rt,int K)
    {
        mn[rt]=K, sz[rt]=r-l+1;
        if(l==r) return;
        int m=l+r>>1; Build(lson,K), Build(rson,K);
    }
    void Modify2(int l,int r,int rt,int a,int cost)
    {
        if(mn[rt]>a) {Ans+=1ll*cost*a*sz[rt], Upd(rt,-a); return;}
        if(l==r) {Ans+=1ll*cost*mn[rt], sz[rt]=0, mn[rt]=INF; return;}
        if(tag[rt]) PushDown(rt);
        int m=l+r>>1;
        Modify2(lson,a,cost), Modify2(rson,a,cost), Update(rt);
    }
    void Modify(int l,int r,int rt,int L,int R,int a,int cost)
    {
        if(L<=l && r<=R) {Modify2(l,r,rt,a,cost); return;}
        if(tag[rt]) PushDown(rt);
        int m=l+r>>1;
        if(L<=m) Modify(lson,L,R,a,cost);
        if(m<R) Modify(rson,L,R,a,cost);
        Update(rt);
    }
}T;

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}

int main()
{
    #define S 1,n,1
    const int n=read(),K=read(),m=read();
    for(int i=1; i<=m; ++i) A[i]=(Node){read(),read(),read(),read()};
    std::sort(A+1,A+1+m), T.Build(S,K);
    for(int i=1; i<=m; ++i) T.Modify(S,A[i].l,A[i].r,A[i].num,A[i].cost);
    printf("%I64d\n",T.Ans);

    return 0;
}

D.Garbage Disposal(模拟)

模拟一下就行了。
因为刚开始读错题还写了个二分=v=

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;

int A[N];

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}
bool Check(LL x,int n,int K)
{
    LL las=0;
    for(int i=1; i<=n; ++i)
    {
        LL need=(las+K-1)/K; las=std::max(0ll,A[i]-(need*K-las));
        x-=need;
        if(x<0) return 0;
    }
    return x>=(las+K-1)/K;//不要写x*K!!!
}

signed main()
{
    int n=read(),K=read(); LL sum=0;
    for(int i=1; i<=n; ++i) sum+=A[i]=read();
    LL l=0,r=3e18,mid,ans=r;
    while(l<=r)
        if(Check(mid=l+r>>1,n,K)) ans=mid, r=mid-1;
        else l=mid+1;
    printf("%I64d\n",ans);

    return 0;
}

E.Getting Deals Done(二分)

显然答案是可以三分的。但是答案是整数三分有点麻烦。
考虑能不能二分一个答案\(mid\)是否可行。如果至少选\(mid\)个,那么要选的肯定是最便宜的\(mid\)个物品。那么模拟一下就行了。

//46ms  2200KB(离散化的版本,那个写的太丑了留这个代码叭)
#include <cstdio>
#include <cctype>
#include <algorithm>
#define gc() getchar()
typedef long long LL;
const int N=2e5+5;

int A[N],ref[N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}
inline LL readll()
{
    LL now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}
bool Check(int x,int n,int m,LL T)
{
    LL sum=0;//longlongaaaTAT
    for(int res=0,now=0,i=1,val=ref[x]; i<=n; ++i)
        if(A[i]<=val)
        {
            if((T-=A[i])<0) return 0;
            if(++res>=x) return 1;
            sum+=A[i];
            if(++now==m) now=0, T-=sum, sum=0;
        }
    return 0;
}

int main()
{
    ref[0]=1;
    for(int Ts=read(); Ts--; )
    {
        const int n=read(),m=read(); const LL t=readll();
        for(int i=1; i<=n; ++i) ref[i]=A[i]=read();
        std::sort(ref+1,ref+1+n);
        int l=1,r=n,mid,ans=0;
        while(l<=r)
            if(Check(mid=l+r>>1,n,m,t)) ans=mid, l=mid+1;
            else r=mid-1;
        printf("%d %d\n",ans,ref[ans]);
    }

    return 0;
}

F.Debate(贪心)

记四种人分别是\(1,2,3,4\)。显然\(2,3\)可以同时选,然后选一个\(4\)可以多选一个\(1/2+3\)。排序从大到小选就行了。

//46ms  6100KB
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <functional>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=4e5+5;

int val[4][N];

inline int read()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now;
}
inline int read01()
{
    int now=0;register char c=gc();
    for(;!isdigit(c);c=gc());
    for(;isdigit(c);now=now*2+c-48,c=gc());
    return now;
}

int main()
{
    const int n=read();
    int cnt[4]={0};
    for(int i=1,type; i<=n; ++i) type=read01(), val[type][++cnt[type]]=read();
    if(!cnt[3]&&(!cnt[1]||!cnt[2])) return puts("0"),0;
    for(int i=0; i<4; ++i) std::sort(val[i]+1,val[i]+cnt[i]+1,std::greater<int>());
    int p0=1,p1=1,p2=1,p3=1,ans=0;
    for(; p1<=cnt[1]&&p2<=cnt[2]; ans+=val[1][p1++]+val[2][p2++]);
    for(int i=1; i<=cnt[3]; ++i)
    {
        if(val[1][p1]+val[2][p2]>val[0][p0]) ans+=val[1][p1++]+val[2][p2++];
        else ans+=val[0][p0++];
        ans+=val[3][i];
    }
    printf("%d\n",ans);

    return 0;
}

H.BerOS File Suggestion(后缀自动机)

怎么写AC自动机、写Hash的都有... 这不是BZOJ2780吗?
粘过代码来就完了。然而我粘错了WA了两次。

//77ms  17500KB
#include <cstdio>
#include <cctype>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define pc putchar
#define gc() getchar()
typedef long long LL;
const int N=10005*10;
using namespace std;

int mp[233];
string str[10005];
struct Suffix_Automaton
{
    int tot,las,fa[N],len[N],son[N][40],cnt[N],bef[N];

    void Insert(int c,int now)
    {
        int np=++tot,p=las; len[las=np]=len[p]+1;
        for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
        if(!p) fa[np]=1;
        else
        {
            int q=son[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else
            {
                int nq=++tot;
                len[nq]=len[p]+1, bef[nq]=bef[q], cnt[nq]=cnt[q];
                memcpy(son[nq],son[q],sizeof son[q]);
                fa[nq]=fa[q], fa[q]=fa[np]=nq;
                for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
            }
        }
        for(; bef[np]!=now&&np; np=fa[np])
            ++cnt[np], bef[np]=now;
    }
    void Query(char *s,int l)
    {
        int x=1;
        for(int i=0; i<l; ++i) x=son[x][mp[s[i]]];
        cout << cnt[x] << ' ' << str[bef[x]] << '\n';
    }
}sam;

inline int read()
{
    int now=0,f=1;register char c=gc();
    for(;!isdigit(c);c=='-'&&(f=-1),c=gc());
    for(;isdigit(c);now=now*10+c-48,c=gc());
    return now*f;
}

int main()
{
    static char s[233];
    int cnt=0; mp['.']=cnt++;
    for(int i='0'; i<='9'; ++i) mp[i]=cnt++;
    for(int i='a'; i<='z'; ++i) mp[i]=cnt++;
    int n=read(); sam.tot=1;
    for(int i=1; i<=n; ++i)
    {
        scanf("%s",s), str[i]=s;
        sam.las=1;
        for(int j=0,l=strlen(s); j<l; ++j) sam.Insert(mp[s[j]],i);
    }
    str[0]="-";
    for(int Q=read(); Q--; scanf("%s",s), sam.Query(s,strlen(s)));

    return 0;
}

I.Privatization of Roads in Berland(网络流)

\(Description\)
给定一张\(n\)个点\(m\)条边的无向图,以及一个整数\(k\)。你需要给每一条边染一种颜色。颜色种类无限多,每种颜色最多用两次,且对于任意一个点,和它相连的边的颜色不能超过\(k\)种。求一种可行的染色方案。
\(n,m\leq600\)。
\(Solution\)
设\(dgr_i\)为\(i\)的度数。那么如果\(dgr_i\leq k\),\(i\)连的边的颜色是什么都无所谓。否则需要让\(2(dgr_i-k)\)条边两两配对。
一条边在一个点处配对了就不能在另一个点处配对。对每条边\(i\ (u,v)\)连边\((u\to i,1),(v\to i,1),(i\to T,1)\),每个点\(x\)连边\((S\to x,\max(0,\ 2(d_x-k)))\),看最大流是否等于\(\sum\max(0,\ 2(d_x-k))\)即可。
不写代码惹。



2018-2019 ICPC, NEERC, Southern Subregional Contest

原文地址:https://www.cnblogs.com/SovietPower/p/10772320.html

时间: 2024-08-24 14:28:31

2018-2019 ICPC, NEERC, Southern Subregional Contest的相关文章

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) 体验记

原文链接https://www.cnblogs.com/zhouzhendong/p/CF1070.html 比赛网址:http://codeforces.com/contest/1070 感受 本来只打算玩玩的. 结果玩的海星. 我做 A 题的时候可能比较浮躁吧,各种傻错误,爆了 7 个罚时. 我 A 还没过,cly 神仙已经把 CDK 切光了. 4点半过一会儿,各自回家.cly 要剃头,就咕咕咕了.我本来也要剃的,后来临时决定先打题. 然后过了 A ,顺手切掉了 H 和 F ,开了 E ,猜

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred)

http://codeforces.com/contest/1070 A 给你一个d和s,求一个最小的数,使的能整除d,并且每位数的和为s. 如果确定了某n位数取模d的值,那么再计算同样的n位数,取模d也是相同的值时,就多此一举了.比如10%2 == 0  20%2 == 0  同样是两位数,取模2都是等于0.所以取最小的就可以了. 1 #include <bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 const

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror) Partial Solution

从这里开始 题目列表 瞎扯 Problem A Find a Number Problem B Berkomnadzor Problem C Cloud Computing Problem D Garbage Disposal Problem E Getting Deals Done Problem F Debate Problem G Monsters and Potions Problem H BerOS File Suggestion Problem I Privatization of

2018-2019 ICPC, NEERC, Southern Subregional Contest (Online Mirror, ACM-ICPC Rules, Teams Preferred) Solution

A. Find a Number Solved By 2017212212083 题意:$找一个最小的n使得n % d == 0 并且 n 的每一位数字加起来之和为s$ 思路: 定义一个二元组$<d, s>$ 表示当前状态模d的值,以及每一位加起来的值 跑最短路,从$<0, 0>  跑到 <0, s>$ 1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int maxn = 1e5 +

模拟赛小结:2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest

2014-2015 ACM-ICPC, NEERC, Southern Subregional Contest 2019年10月11日 15:30-20:30(Solved 6,Penalty 740) 国庆咸鱼十来天,回来又过了快一个星期,终于和队友约上了模拟赛.(周三拖周四,因为队(fei)友(zhai)们要跑1000米,又拖到周五QAQ) I:00:04.开场翻翻题目,机智如我很快找到一个贪心. D:00:36.看了看现场榜,有人交D.F和M,lh同学已经开F去了,xk同学说他M思路差不多

D. Dog Show 2017-2018 ACM-ICPC, NEERC, Southern Subregional Contest, qualification stage (Online Mirror, ACM-ICPC Rules, Teams Preferred)

http://codeforces.com/contest/847/problem/D 巧妙的贪心 仔细琢磨... 像凸包里的处理 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <time.h> 6 #include <string> 7 #include <set> 8 #includ

NEERC Southern Subregional 2012

NEERC Southern Subregional 2012 Problem B. Chess Championship 题目描述:有两个序列\(a, b\),两个序列都有\(n\)个数,并且这\(2n\)个数两两不同,现在要将这两个序列里的数两两配对,组成\(n\)个数对,要求数对中\(a\)的数比\(b\)的数大的数对个数要比其它的多\(m\)个.问方案数. solution 将这\(2n\)个数从小到大排,预处理出前\(i\)个数中\(a, b\)的个数\(suma, sumb\), \

2013-2014 ACM-ICPC, NEERC, Eastern Subregional Contest PART (7/10)

\[2013-2014\ ACM-ICPC,\ NEERC,\ Eastern\ Subregional\ Contest\] \(A.Podracing\) \(B.The\ battle\ near\ the\ swamp\) 签到 //#pragma comment(linker, "/STACK:1024000000,1024000000") #include<bits/stdc++.h> using namespace std; function<void(

ACM ICPC 2011–2012, NEERC, Northern Subregional Contest J. John’s Inversions(合并排序求逆序数对数)

题目链接:http://codeforces.com/gym/100609/attachments 题目大意:有n张牌,每张牌有红色和蓝色两面,两面分别写了一些数字,同种颜色的任意两个数字若排在前面的数字比排在后面的数字大就叫做一对逆序数.求怎样排序得到的逆序数对最少. 解题思路:其中一种颜色的数字是顺序且这种颜色数字相同时对应的另一种颜色的数字是顺序时得到的逆序数对数最少.难点在于求逆序数对数.因为数量很大O(n^2)复杂度不能满足,这里根据合并排序的原理求解每个数字前面有多少个比它大的数字,