Codeforces Round #542 Div. 1

  A:显然对于起点相同的糖果,应该按终点距离从大到小运。排个序对每个起点取max即可。读题花了一年还wa一发,自闭了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 20010
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;
int dis(int x,int y)
{
	if (x<=y) return y-x;
	else return n-x+y;
}
struct data
{
	int x,y;
	bool operator <(const data&a) const
	{
		return x<a.x||x==a.x&&dis(x,y)>dis(a.x,a.y);
	}
}a[N<<1];
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++) a[i].x=read(),a[i].y=read();
	sort(a+1,a+m+1);
	for (int i=1;i<=n;i++)
	{
		int ans=0;
		for (int j=1;j<=m;j++)
		{
			int t=j;
			while (t<m&&a[t+1].x==a[j].x) t++;
			ans=max(ans,dis(i,a[t].x)+dis(a[t].x,a[t].y)+(t-j)*n);
			j=t;
		}
		printf("%d ",ans);
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  B:考虑构造一个长度为n=2000的序列,前1998项都是0,第1999项是负数,第2000项是正数。设1999项绝对值为y,2000项绝对值为x,则要求n*(x-y)-k=x,也即(n-1)x=k+ny。注意到n和n-1互质,所以y取遍0~n-1后一定能找到一个整数x,其作为答案即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 20010
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;
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();
	for (int i=1;i<=10000;i++)
	if ((n+2000*i)%1999==0)
	{
		cout<<2000<<endl;
		for (int j=1;j<=1998;j++) cout<<0<<' ';
		cout<<-i<<' ';cout<<(n+2000*i)/1999;
		return 0;
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  C:考虑动态添加01时对每个后缀计算贡献(即可以划分成多少个合法字符串)。如果已经有与其本质相同的子串,则贡献为0,这可以建棵trie(也就是反串未压缩的后缀树)来判断。否则设l~r区间的贡献为f[l][r],其从f[l][r-4~r-1]转移而来即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 3010
#define P 1000000007
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,a[N],id[N][N],f[N*N],trie[N*N][2],cnt,ans;
bool isok(int l,int r)
{
	if (a[l]==0&&a[l+1]==0&&a[l+2]==1&&a[l+3]==1) return 0;
	if (a[l]==0&&a[l+1]==1&&a[l+2]==0&&a[l+3]==1) return 0;
	if (a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==0) return 0;
	if (a[l]==1&&a[l+1]==1&&a[l+2]==1&&a[l+3]==1) return 0;
	return 1;
}
//0011 0101 1110 1111 ������ĸ
signed main()
{
#ifndef ONLINE_JUDGE
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
#endif
	n=read();f[0]=1;
	for (int i=1;i<=n;i++)
	{
		a[i]=read();
		int k=0;
		for (int j=i;j>=1;j--)
		{
			if (!trie[k][a[j]])
			{
				trie[k][a[j]]=++cnt;
				k=trie[k][a[j]],id[j][i]=k;
				if (i-j+1==1) f[k]=1;
				else if (i-j+1==2) f[k]=2;
				else if (i-j+1==3) f[k]=4;
				else
				{
					f[k]=(f[id[j][i-1]]+f[id[j][i-2]])%P;
					f[k]=(f[k]+f[id[j][i-3]])%P;
					if (isok(i-3,i)) f[k]=(f[k]+f[id[j][i-4]])%P;
				}
				ans=(ans+f[k])%P;
			}
			else k=trie[k][a[j]],id[j][i]=k;
		}
		printf("%d\n",ans);
	}
	return 0;
	//NOTICE LONG LONG!!!!!
}

  D:显然可以dp,即f[i]为前i位的划分方案数。考虑优化转移。套路的将每个数字最后一次出现位置设为1,倒数第二次设为-1,其余为0,每次需要的就是后缀和<=m的位置之和。这个东西可以分块维护。然而只有在最后5min才想的到分块的,自闭了。

  result:rank 25 rating +121(prediction) 上红辣!!!???

猜你喜欢

转载自www.cnblogs.com/Gloid/p/10428941.html