Codeforces Round #423 Div. 1

  A:暴力赋值即可,并查集维护下一个未被赋值的位置。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 2000010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int T,fa[N],len;
char s[N],ans[N];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	T=read();
	for (int i=1;i<=2000001;i++) fa[i]=i;
	while (T--)
	{
		scanf("%s",s);int m=strlen(s);
		int n=read();
		for (int i=1;i<=n;i++)
		{
			int x=read();
			len=max(len,x+m-1);
			for (int j=find(x);j<=x+m-1;j=find(j))
			ans[j]=s[j-x],fa[j]=find(j+1);
		}
	}
	for (int i=1;i<=len;i++)
	if (find(i)==i) ans[i]='a';
	printf("%s",ans+1);
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:显然应该连成菊花套链。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,k;
bool flag[N];
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	cin>>n>>k;
	if (n%k==2||k==2&&n%k==0) cout<<2*((n-2)/k)+1<<endl;
	else if (n%k==1) cout<<2*((n-1)/k)<<endl;
	else cout<<2*((n-1)/k+1)<<endl;
	for (int i=1;i<=k;i++) flag[i]=1;
	for (int i=k+1;i<n;i++)
	{
		flag[i-k]=0;flag[i]=1;
		printf("%d %d\n",i-k,i);
	}
	for (int i=1;i<=n;i++) if (flag[i]) printf("%d %d\n",n,i);
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:注意到字符集大小很小询问串长度很短,对每种字符每种长度分别维护bit即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
char s[N],t[N];
int n,q,tree[4][11][N];
int trans(char c)
{
	if (c=='A') return 0;
	if (c=='T') return 1;
	if (c=='G') return 2;
	if (c=='C') return 3;
}
int nxt(int x,int m,int r)
{
	if (x>r) x-=m;
	return x+(r-x)/m*m;
}//<=r   u mod m=x mod m 
void add(int x,int m,int k,int p)
{
	while (k<=n)
	{
		tree[x][m][k]+=p;
		int u=(k-1)/m+1;
		u+=u&-u;
		k=(u-1)*m+(k-1)%m+1;
	}
}
int query(int x,int m,int k)
{
	if (k<=0) return 0;
	int s=0;
	while (k>0)
	{
		s+=tree[x][m][k];
		int u=(k-1)/m+1;
		u-=u&-u;
		k=(u-1)*m+(k-1)%m+1;
	}
	return s;
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	scanf("%s",s+1);
	n=strlen(s+1);
	for (int i=1;i<=n;i++)
		for (int j=1;j<=10;j++)
		add(trans(s[i]),j,i,1);
	q=read();
	while (q--)
	{
		int op=read();
		if (op==1)
		{
			int x=read();
			char c=getc();
			for (int j=1;j<=10;j++)
			add(trans(s[x]),j,x,-1),
			add(trans(c),j,x,1);
			s[x]=c;
		}
		else
		{
			int l=read(),r=read();
			scanf("%s",t);int m=strlen(t),ans=0;
			for (int i=0;i<m;i++) ans+=query(trans(t[i]),m,nxt(l+i,m,r))-query(trans(t[i]),m,l+i-m);
			printf("%d\n",ans);
		}
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  D:先跑一棵MST。对于不在MST中的边,显然要使其满足条件,其权值应比MST中两点路径上的权值最大值小。倍增查一下即可。对于在MST上的边,其权值应比所有覆盖该边的非树边权值小。从小到大进行树链覆盖,并查集维护每个点第一个未被覆盖的祖先即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 200010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,p[N],dfn[N],f[N],deep[N],fa[N][19],E[N],ans[N],len[N][20],t,cnt;
bool flag[N];
struct data{int to,nxt,i,len;
}edge[N<<1];
struct data2
{
	int x,y,z,i;
	bool operator <(const data2&a) const
	{
		return z<a.z;
	}
}e[N]; 
void addedge(int x,int y,int i,int z){t++;edge[t].to=y,edge[t].nxt=p[x],edge[t].i=i,edge[t].len=z,p[x]=t;}
int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
void dfs(int k)
{
	for (int i=p[k];i;i=edge[i].nxt)
	if (edge[i].to!=fa[k][0])
	{
		fa[edge[i].to][0]=k;
		E[edge[i].to]=edge[i].i;
		len[edge[i].to][0]=edge[i].len;
		deep[edge[i].to]=deep[k]+1;
		dfs(edge[i].to);
	}
}
int lca(int x,int y)
{
	if (deep[x]<deep[y]) swap(x,y);
	for (int j=18;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
	if (x==y) return x;
	for (int j=18;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
	return fa[x][0];
}
void cover(int x,int u,int y)
{
	x=find(x);
	while (deep[x]>deep[u])
	{
		ans[E[x]]=y-1;
		f[x]=find(fa[x][0]);
		x=find(x);
	}
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(),m=read();
	for (int i=1;i<=m;i++) e[i].x=read(),e[i].y=read(),e[i].z=read(),e[i].i=i;
	sort(e+1,e+m+1);
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=m;i++)
	if (find(e[i].x)!=find(e[i].y))
	{
		f[find(e[i].x)]=find(e[i].y);
		addedge(e[i].x,e[i].y,e[i].i,e[i].z),addedge(e[i].y,e[i].x,e[i].i,e[i].z);
		flag[i]=1;
	}
	fa[1][0]=1;dfs(1);
	for (int j=1;j<=18;j++)
		for (int i=1;i<=n;i++)
		fa[i][j]=fa[fa[i][j-1]][j-1],
		len[i][j]=max(len[i][j-1],len[fa[i][j-1]][j-1]);
	for (int i=1;i<=n;i++) f[i]=i;
	for (int i=1;i<=m;i++)
	if (!flag[i])
	{
		int x=e[i].x,y=e[i].y,u=lca(x,y);
		cover(x,u,e[i].z);cover(y,u,e[i].z);
		for (int j=18;~j;j--)
		{
			if (deep[fa[x][j]]>=deep[u]) ans[e[i].i]=max(ans[e[i].i],len[x][j]),x=fa[x][j];
			if (deep[fa[y][j]]>=deep[u]) ans[e[i].i]=max(ans[e[i].i],len[y][j]),y=fa[y][j];
		}
		ans[e[i].i]--;
	}
	for (int i=2;i<=n;i++) if (find(i)==i) ans[E[i]]=-1;
	for (int i=1;i<=m;i++) printf("%d ",ans[i]);
	return 0;
	//NOTICE LONG LONG!!!!!
}

  E:考虑如何判断某循环节长度是否合法,显然只要不存在字符不同(不包括?)的距离为其倍数的两位置即可。考虑求每种距离各有多少对字符不同。https://www.cnblogs.com/Gloid/p/9452441.html。然后暴力枚举倍数判断即可。略卡常,似乎FFT比NTT快。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1100000
#define P 998244353
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int T,n,a[N],b[N],c[N],f[N],r[N],ans[N];
char s[N];
void inc(int &x,int y){x+=y;if (x>=P) x-=P;}
int ksm(int a,int k)
{
    int s=1;
    for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
    return s;
}
int inv(int a){return ksm(a,P-2);}
void DFT(int *a,int n,int g)
{
    for (int i=0;i<n;i++) r[i]=(r[i>>1]>>1)|(i&1)*(n>>1);
    for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
    for (int i=2;i<=n;i<<=1)
    {
        int wn=ksm(g,(P-1)/i);
        for (int j=0;j<n;j+=i)
        {
            int w=1;
            for (int k=j;k<j+(i>>1);k++,w=1ll*w*wn%P)
            {
                int x=a[k],y=1ll*w*a[k+(i>>1)]%P;
                a[k]=(x+y)%P,a[k+(i>>1)]=(x-y+P)%P;
            }
        }
    }
}
void mul(int *a,int *b,int n)
{
	DFT(a,n,3),DFT(b,n,3);
	for (int i=0;i<n;i++) a[i]=1ll*a[i]*b[i]%P;
	DFT(a,n,inv(3));
	int t=inv(n);
	for (int i=0;i<n;i++) a[i]=1ll*a[i]*t%P;
}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	T=read();
	while (T--)
	{
		n=read();scanf("%s",s+1);
		int t=1;while (t<(n<<1)) t<<=1;
		for (int i=0;i<t;i++) a[i]=b[i]=c[i]=0;
		for (int i=0;i<t;i++) f[i]=0;
		for (int i=1;i<=n;i++) if (s[i]=='V') a[i]=1;
		for (int i=0;i<n;i++) f[i]=2*(s[n-i]=='K');
		mul(a,f,t);
		for (int i=0;i<t;i++) f[i]=0;
		for (int i=1;i<=n;i++) if (s[i]=='K') b[i]=8;
		for (int i=0;i<n;i++) f[i]=s[n-i]=='V';
		mul(b,f,t);
		for (int i=0;i<t;i++) f[i]=0;
		for (int i=1;i<=n;i++) if (s[i]=='V') c[i]=1;
		for (int i=0;i<n;i++) f[i]=(P-4*(s[n-i]=='K'))%P;
		mul(c,f,t);
		int u=0;
		for (int i=1;i<=n;i++)
		{
			bool flag=0;
			for (int j=i;j<=n;j+=i)
			if (a[n-j]+b[n-j]+c[n-j]) {flag=1;break;}
			if (!flag) ans[++u]=i;
		}
		printf("%d\n",u);
		for (int i=1;i<=u;i++) printf("%d ",ans[i]);printf("\n");
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  F:容易想到拆点bfs,点数过多。注意到只要边还没消失就可以在上面反复横跳,每隔2s就能返回一次原来的点。于是只将每个点根据时刻奇偶性拆成两个点。拆完后重建一下图,根据所连点的奇偶性稍微调整一下边的起止时间。

  这样可以在一个点逗留的时间段是连续(以2s为单位)的。考虑求出每个点最早什么时候能到,最晚什么时候走,这样就能得到答案了。

  用边更新答案。考虑将所有已确定最早能何时经过的边扔进小根堆。每次取出堆顶对该边终点进行更新。然后根据该终点信息更新以其为起点的所有尚未确定最早经过时间的边。若该点最晚离开时间超过了边的出现时间,就确定其最早经过时间。容易发现这样得到的时间一定是最优的,因为要么是其出现时间,要么是当前最早经过的边的时间。否则不管。为保证复杂度需要提前将以某点为起点的边按出现时间从小到大排序。大约就是跑了个魔改dij。

  另一种等价实现方法是一开始就把所有边扔进堆,具体见代码。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<cassert>
using namespace std;
#define ll long long
#define N 500010
#define inf 1010000000
#define odd(i) ((i)+n)
#define even(i) (i)
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) 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 c=getchar();
	while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}
int n,m,t,first[N<<1],last[N<<1],cur[N<<1];
struct data
{
	int x,y,l,r;
	bool operator <(const data&a) const
	{
		return l>a.l; 
	}
};
priority_queue<data> q;
vector<data> e[N<<1];
void addedge(int x,int y,int l,int r){if (l>r) return;t++;q.push((data){x,y,l,r});}
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read(),m=read();
	for (int i=1;i<=m;i++)
	{
		int x=read(),y=read(),l=read(),r=read();
		addedge(odd(x),even(y),l+(l%2==0),r-(r&1));
		addedge(even(x),odd(y),l+(l&1),r-(r%2==0));
		addedge(odd(y),even(x),l+(l%2==0),r-(r&1));
		addedge(even(y),odd(x),l+(l&1),r-(r%2==0));
	}
	for (int i=1;i<=n*2;i++) first[i]=inf,last[i]=-1;
	first[1]=last[1]=0;
	while (!q.empty())
	{
		data u=q.top();q.pop();
		if (last[u.x]>=u.l)
		{
			if (first[u.x]>=u.r) continue;
			u.l=max(first[u.x],u.l);
			last[u.y]=max(last[u.y],u.r);
			first[u.y]=min(first[u.y],u.l+1);
			while (cur[u.y]<e[u.y].size()&&last[u.y]>=e[u.y][cur[u.y]].l)
			{
				data v=e[u.y][cur[u.y]++];
				if (first[u.y]>=v.r) continue;
				v.l=max(first[v.x],v.l);
				last[v.y]=max(last[v.y],v.r);
				first[v.y]=min(first[v.y],v.l+1);
				q.push(v);
			}
		}
		else e[u.x].push_back(u);
	}
	//for (int i=1;i<=n*2;i++) cout<<first[i]<<' '<<last[i]<<endl;
	if (min(first[odd(n)],first[even(n)])>=inf) cout<<-1;
	else cout<<min(first[odd(n)],first[even(n)]);
	return 0;
	//NOTICE LONG LONG!!!!!
}

 

  

 

posted @ 2019-03-15 01:32  Gloid  阅读(158)  评论(0编辑  收藏  举报