• 2018-2019 ICPC, NEERC, Southern Subregional Contest



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

    比赛链接

    VP了一场最近的没做过的ACM。ACM的Online Mirror好少啊...
    B题看不懂样例=-= K题签到题。其它题咕咕了。

    A.Find a Number(BFS)

    先要想到令(f[i][j])表示模(d)余数为(i),数位和为(j)的最小数。状态数是OK的。
    然后每次转移就是在后面加上(0sim 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))(mngt a)时,直接区间减(a)统计一下答案就行了;当(mnleq 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
    ",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
    ",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
    ",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
    ",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]] << '
    ';
    	}
    }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,mleq600)
    (Solution)
    (dgr_i)(i)的度数。那么如果(dgr_ileq k)(i)连的边的颜色是什么都无所谓。否则需要让(2(dgr_i-k))条边两两配对。
    一条边在一个点处配对了就不能在另一个点处配对。对每条边(i (u,v))连边((u o i,1),(v o i,1),(i o T,1)),每个点(x)连边((S o x,max(0, 2(d_x-k)))),看最大流是否等于(summax(0, 2(d_x-k)))即可。
    不写代码惹。


  • 相关阅读:
    【Ubuntu 笔记】翻译 32.1 Job Control
    【Class 学习笔记】 浮点数的储存,运算
    【Ubuntu学习笔记】 安装篇-锐捷、scim、root改密码
    【Ubuntu学习笔记】安装篇-网络配置遇到的问题
    MySQL增删改查
    Spring MVC详解
    SSH和SSM对比总结
    hibernate工作原理
    JavaBean与xml互转的方法详解
    spring MVC如何获取session传值到前台
  • 原文地址:https://www.cnblogs.com/SovietPower/p/10772320.html
Copyright © 2020-2023  润新知