2019.06.05 【NOIP提高组】模拟 A 组 比赛总结

题目

矩阵

Description

在麦克雷的面前出现了一个有nm个格子的矩阵,每个格子用“.”或“#”表示,“.”表示这个格子可以放东西,“#”则表示这个格子不能放东西。现在他拿着一条12大小的木棒,好奇的他想知道对于一些子矩阵,有多少种放木棒的方案。

Input

第一行包含 2 个正整数 n,m。
接下来 n 行每行包含 m 个字符“.”或“#”。
第n+1行包含1个正整数q,表示询问次数。
接下来q行每行包含4个正整数r1,c1,r2,c2,分别表示询问的子矩阵的左上格子和右下格子的位置。

Output

输出共 q 行,每行包含 1 个整数,表示该询问的方案数。

Sample Input

5 8
…#…#
.#…
##.#…
##…#.##

4
1 1 2 3
4 1 4 1
1 2 4 5
2 5 5 8

Sample Output

4
0
10
15
在这里插入图片描述

Data Constraint

30%:q<=100
100%:q<=10^5,1<=n,m<=500


整除

Description

麦克雷有一个1~n的排列,他想知道对于一些区间,有多少对区间内的数(x,y),满足x能被y整除。

Input

第一行包含2个正整数n,m。表示有n个数,m个询问。
接下来一行包含n个正整数,表示麦克雷有的数列。
接下来m行每行包含2个正整数l,r。表示询问区间[l,r]。

Output

共 m 行,每行一个整数,表示满足条件的对数。

Sample Input

10 9
1 2 3 4 5 6 7 8 9 10
1 10
2 9
3 8
4 7
5 6
2 2
9 10
5 10
4 10

Sample Output

27
14
8
4
2
1
2
7
9

Data Constraint

30%:1<=n,m<=100
100%:1<=n,m<=2*10^5,1<=pi<=n


Gre

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

3
1 1
2 2
5 2

Sample Output

a
CiYe
aabaa

Data Constraint

在这里插入图片描述


总结

其实今天的前2题原来是靶形数独最优贸易,但是我们都做过了,XC才换了题。于是我失去了一次200+的机会
T1一眼出正解,二维前缀和,分别处理向上和向左放木条的情况就可以了。
T2半天看不懂题意,直到比赛结束也搞不懂这是什么东东。好不容易发现 (x,y) 是指区间 [l…r] 内的任意2个数,又被数据给卡住了:

10 9
1 2 3 4 5 6 7 8 9 10
1 10
2 9
3 8
4 7
5 6
2 2
9 10
5 10
4 10

加粗的[4…7]对应的答案是4。
为什么是4?明明它们都不能相互整除的呀!
懵逼的我于是转到T3。
看完样例后,我开始画不同的k的情况。
由于前缀和后缀都是太简单的,所以无论从前面还是后面数,每一个字符出现次数都是不一样的。
当然,我们只会用前k种字符。
这样的话,前后应该就是回文的了,一个合法的答案应该是这样的:
a a a a a a a a a a ⎵ 11 个 &ThickSpace; b b b b b ⎵ 5 个 &ThickSpace; c c ⎵ 2 个 &ThickSpace; d ⎵ 1 个 &ThickSpace; c c ⎵ 2 个 b b b b b ⎵ 5 个 &ThickSpace; a a a a a a a a a a ⎵ 11 个 \it \underbrace{aaaaaaaaaa}_{11个}\;\underbrace{bbbbb}_{5个}\;\underbrace{cc}_{2个}\;\underbrace{d}_{1个}\;\underbrace{cc}_{2个}\underbrace{bbbbb}_{5个}\;\underbrace{aaaaaaaaaa}_{11个} 11 aaaaaaaaaa5 bbbbb2 cc1 d2 cc5 bbbbb11 aaaaaaaaaa
前面多余的地方再全部填a。
但我的直觉告诉我,这题不可能这么简单,果然——
得分:100+0+34=134


题解

T1

前缀和处理每一个格子向上、向左放置木棒的方案数。

T2

其实我只是忘记考虑了自己整除自己的情况……我的30分啊……
可以发现,[l…r]的答案=[1…r]的答案-[1…l-1]的答案+[1…l-1]和[l…r]的倍数关系。
但是单独处理[1…l-1]和[l…r]的倍数关系是很困难的,因此我们可以把它并入[1…l-1]的答案中。
对于每一个询问[l…r],可以将其抽象为二维偏序问题,用排序+数据结构处理。

我们先将询问按右端点升序排序。
并按原序列顺序从 1 往 n 做,每做到一个位置,便在它左边的数中与它有倍数关系的数的位置加一。并统计已经加的次数。
那么每当我们遇到一个右端点与当前做的位置相同时,就可以直接将当前总共加的次数减去起点到左端点的区间的和。
单点修改和区间求和可以用树状数组

T3

找规律(其实也可以理性证明),发现从n到1可以这么放:(此处的abcd应对应原串中的dcba)
先1个a,再1个ab,1个abc,1个abcd……放到第k个字母出现为止;
接着从第k-1个字母开始放,……2个abcd,2个abc,2个ab,2个a;
开头剩余的位置全部放a。


CODE

T1

#include<cstdio>
using namespace std;
#define N 505
bool b[N][N];
int up[N][N],left[N][N];
int main()
{
    
    
	int n,m,q,i,j,x,y;char ch;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
	{
    
    
		scanf("\n");
		for(j=1;j<=m;j++)
		{
    
    
			ch=getchar();
			if(ch=='.')
			{
    
    
				b[i][j]=1;
				if(b[i-1][j]) up[i][j]=1;
				if(b[i][j-1]) left[i][j]=1;
			}
			up[i][j]+=up[i-1][j]+up[i][j-1]-up[i-1][j-1];
			left[i][j]+=left[i-1][j]+left[i][j-1]-left[i-1][j-1];
		}
	}
	scanf("%d",&q);
	while(q--)
	{
    
    
		scanf("%d%d%d%d",&i,&j,&x,&y);
		printf("%d\n",up[x][y]-up[i][y]-up[x][j-1]+up[i][j-1]+left[x][y]-left[x][j]-left[i-1][y]+left[i-1][j]);
	}
	return 0;
}

T2

#include<cstdio>
#include<algorithm>
using namespace std;
#define lowbit(k) k&-k
#define N 200005
int n,a[N],s[N],id[N],ans[N];
struct number
{
    
    
	number *nex;
	int num;
	number(){
    
    nex=NULL,num=0;}
}*fir[N],*p;
struct query
{
    
    
	int l,r,id;
}ask[N];
inline bool cmp(query x,query y){
    
    return x.r<y.r;}
inline char gc()
{
    
    
	static char buf[N],*p1=buf,*p2=buf;
	return p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x)
{
    
    
	char ch;
	while(ch=gc(),ch<'0'||ch>'9');x=ch-'0';
	while(ch=gc(),ch>='0'&&ch<='9') x=x*10+ch-'0';
}
inline void add(int k){
    
    for(;k<=n;k+=lowbit(k)) s[k]++;}
inline int qry(int k)
{
    
    
	int res=0;
	for(;k;k-=lowbit(k)) res+=s[k];
	return res;
}
int main()
{
    
    
	int m,i,j,k,sum=0;
	read(n),read(m);
	for(i=1;i<=n;i++) read(a[i]),id[a[i]]=i,fir[i]=NULL;
	for(i=1;i<=m;i++) read(ask[i].l),read(ask[i].r),ask[i].id=i;
	sort(ask+1,ask+m+1,cmp);
	for(i=k=1;k<=m;i++)
	{
    
    
		p=fir[i];
		while(p) add(p->num),sum++,p=p->nex;
		for(j=a[i];j<=n;j+=a[i])
			if(id[j]>i)
			{
    
    
				p=new number;
				p->num=i,p->nex=fir[id[j]];
				fir[id[j]]=p;
			}
			else add(id[j]),sum++;
		while(k<=m&&i==ask[k].r)
		{
    
    
			ans[ask[k].id]=sum-qry(ask[k].l-1);
			k++;
		}
	}
	for(i=1;i<=m;i++) printf("%d\n",ans[i]);
	return 0;
}

T3

#include<cstdio>
using namespace std;
#define N 100005
int s[30];
char ch[N];
int main()
{
    
    
	freopen("gre.in","r",stdin);
	freopen("gre.out","w",stdout);
	int q,n,m,i,j,k;
	scanf("%d",&q);
	for(i=1;i<27;i++) s[i]=s[i-1]+i*3-2;
	while(q--)
	{
    
    
		scanf("%d%d",&n,&m);
		if(s[m]>n){
    
    puts("CiYe");continue;}
		for(i=1,k=n;i<=m;i++)
			for(j=0;j<i;j++)
				ch[k--]=j+'a';
		for(i=m-1;i>0;i--)
		{
    
    
			for(j=0;j<i;j++)
				ch[k--]=j+'a';
			for(j=0;j<i;j++)
				ch[k--]=j+'a';
		}
		while(k>0) ch[k--]='a';
		for(i=1;i<=n;i++) putchar(ch[i]);
		putchar('\n');
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/huangzihaoal/article/details/90945742
今日推荐