Codeforces Educational Codeforces Round 48

模拟题真实难…呕

A.Death Note

题意,给你一本书和一个m,每页上可以写m个名字,写满就要翻页。再给你n个数字,第i天要写ai个名字。问你每天各要翻几页?

模拟题,没啥好说的。

B.Segment Occurrences

题意,给你两个字符串s和t。问在s的[l,r]中t出现的次数是多少。又是模拟题,为了方便起见,我们考虑从s中的i位置开始接下来的连续的一串字母是不是和t相同,如果是,说明这个位置开始是可以出现t的。我们对它做一下前缀和,就可以轻松应付大量的询问次数。

对于询问[l,r],我们将r处理为r’=r-t.length()+1。然后如果此时r’已经到l的左边,那么无解,否则ans=sum[r’]-sum[l-1]。

#include
#include
using namespace std;

#define MAX(x,y) (((x)>(y))?(x):(y))
string s,t;
int lens,lent,q;
int num[6005];
int main()
{
	cin>>lens>>lent>>q;
	cin>>s>>t;
	memset(num,0,sizeof(num));
	for(int i=0;i<=lens-lent;i++)
	{
		int flag=0;
		for(int j=0;j>l>>r;
		r=r-lent+1;
		if(r

C.天下第一垃圾模拟题

看到小标题了吗?好,我们看下一题。

D. Vasya And The Matrix

给你一个n*m的矩阵。然后分别给你每行和每列的xor,问你这个矩阵是什么。如不存在输出NO。

我看到第一反应是全部填0,然后右边和下边填对应的数,最后确定右下角的格子是否存在这样的数。但是我没办法证明这个算法是否正确,所以我没这么做。听说是可以过的,希望各位大佬教我证明。

我这边因为看到xor,所以想到拆位。我们考虑一个base=2^a,穷举base直到超出范围,分别统计每一位每个矩阵的格子里为1还是0,最后加起来得到最终结果。

这样说有点抽象,我们举个例子。

比方说题目是这样(x是要求的数,边上的数字是异或和)
□ 5 3 13
2 x x x
9 x x x

转换成二进制

□□□□ 0101 0011 1101
0010 xxxx xxxx xxxx
1001 xxxx xxxx xxxx

我们先拆base=2^0=1

□ 1 1 1
0 x x x
1 x x x

显然,对于异或和为1的某行(或某列),其中的1的个数应该是奇数,反之为偶数个,所以横着的1的个数和竖着的1的个数的奇偶应该相同。否则如果横着是奇数,竖着是偶数,那么我们用上面的推论,可以分别得出拆位矩阵中1的个数既是奇数个,又是偶数个,矛盾,vice verse。

当奇偶相同以后,我们用以下的策略填:

1.先找行1和列1的交汇格填1,这样能解决同样多个行1和列1

□ 1 1 1
0 x x x
1 1 x x

2.由于上面的推论,一定剩下偶数个行1(或列1),那么把它们填在同列(同行),因为偶数个所以不会影响所填的列(行)的状态。

□ 1 1 1
0 x 1 1
1 1 x x

3.其余位置填0

□ 1 1 1
0 0 1 1
1 1 0 0

最后把表更新进答案就完事了

#include
#include
using namespace std;

#define LL long long
LL ans[105][105];
int row[105],col[105];
LL a[105],b[105];
LL n,m;
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)cin>>a[i];
	for(int i=1;i<=m;i++)cin>>b[i];
	memset(ans,0,sizeof(ans));
	long long base=1;
	while(base<1e9+7)
	{
		memset(row,0,sizeof(row));
		memset(col,0,sizeof(col));
		int cntr=0,cntc=0;
		for(int i=1;i<=n;i++)if(a[i]&base)row[i]=1,cntr++;
		for(int i=1;i<=m;i++)if(b[i]&base)col[i]=1,cntc++;
		if((cntr&1)^(cntc&1))break;
		
		if(cntr>cntc)
		{
			int cnt=cntc;
			int pntr=0,pntc=0;
			while(cnt--)
			{
				pntr++;
				pntc++;
				while(!row[pntr])pntr++;
				while(!col[pntc])pntc++;
				ans[pntr][pntc]+=base;
			}
			cnt=cntr-cntc;
			while(cnt--)
			{
				if(cntc==0)pntc=1;
				pntr++;
				while(!row[pntr])pntr++;
				ans[pntr][pntc]+=base;
			}
		}
		else
		{
			int cnt=cntr;
			int pntr=0,pntc=0;
			while(cnt--)
			{
				pntr++;
				pntc++;
				while(!row[pntr])pntr++;
				while(!col[pntc])pntc++;
				ans[pntr][pntc]+=base;
			}
			cnt=cntc-cntr;
			while(cnt--)
			{
				if(cntr==0)pntr=1;
				pntc++;
				while(!col[pntc])pntc++;
				ans[pntr][pntc]+=base;
			}
		}
		
		base=base*2;
	}
	if(base<1e9+7)cout<<"NO"<

补充对于填0方案的证明:

首先,我们不妨设两边分别为a1,a2…an;b1,b2…bm。

首先,如果这里写图片描述,那么答案一定是NO。
因为a1⊕a2⊕…⊕an和b1⊕b2⊕…⊕bm分别是矩阵中所有元素的异或和。如果他们不相等,那么显然是矛盾的。于是我们得到:

a1⊕a2⊕…⊕an⊕b1⊕b2⊕…⊕bm=0 (1)

接下来再看题目,对于题目:

□□ b1 b2 … bm
a1
a2

an

我们除了matrix[1][1]之外按照以下的方案填写(因为排版,所有0用00表示):

□□ b1 b2 … bm
a1 xx b2 … bm
a2 a2 00 … 00
… … … … …
an an 00 … 00

最后只剩下matrix[1][1]没有解决,我们希望构造出这一个解。由题意,不难得出:

matrix[1][1]⊕a2⊕…⊕an=b1 (2)

matrix[1][1]⊕b2⊕…⊕bm=a2 (3)

移项后得到:

matrix[1][1]=a2⊕…⊕an⊕b1 (4)

matrix[1][1]=b2⊕…⊕bm⊕a2 (5)

好的,那么接下来这边只需要证明(4)(5)的右边相等即可。此时我们对
a1⊕a2⊕…⊕an⊕b1⊕b2⊕…⊕bm=0(1)进行变形,得到:

a2⊕…⊕an⊕b1 = b2⊕…⊕bm⊕a2 = matrix[1][1]

那么说明这样的matrix[1][1]是存在且唯一的,于是证明完毕。

E.Rest in the Shades

看似很复杂的一道题,其实还是模拟。。

题意是给你一个匀速移动的光源,再给你一些屏障(在同一条线上),询问一些点无法被光源照射的时长。这道题因为有两组大型数据(屏障,点),所以必定是对其中一个进行预处理。那么我们不难想到,不妨将询问点作为光源,反向处理,其实本质是一样的。

为了提高运行效率,我们再处理一下前缀和,用二分加速一下(好像不二分的话会TLE),花上大量的时间去模拟。叮!AC!

特别提醒一下。我打二分的时候一直忘记要把上下界定在答案外面,这边我调了好久才调对,所以略作提醒。此外,用&判断奇偶性的时候,记住&的优先级是低于==的,所以判断为偶数的时候要加括号。

#include
#include
using namespace std;

const double EPS=1e-6;
double s,a,b,t,l,r;
long long n,q,tmp;
double sum[400005],fence[400005],x,y;

void read(long long &x)
{
	x=0;long long f=-1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return;
}

bool equ(double a,double b)
{
	if(fabs(a-b)>1;
		if(fence[mid]>x)rr=mid;
		else ll=mid;
	}
	return rr;
}

int finden(double x)
{
	int ll=0,rr=2*n+1;
	while(ll>1;
		if(fence[mid]>x)rr=mid;
		else ll=mid;
	}
	return ll;
}

int main()
{
	cin>>s>>a>>b;
	t=b-a;
	
	read(n);
	sum[0]=0;
	for(int i=1;i<=2*n;i++)
	{
		read(tmp);
		fence[i]=tmp;
		sum[i]=sum[i-1];
		if(i%2==0)sum[i]+=fence[i]-fence[i-1];
	 } 
	 fence[0]=0;fence[2*n+1]=1e10+9;
	 
	 read(q);
	 for(int i=0;ifence[2*n]||r

你可能感兴趣的:(CF)