题目
矩阵
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
个
  
b
b
b
b
b
⎵
5
个
  
c
c
⎵
2
个
  
d
⎵
1
个
  
c
c
⎵
2
个
b
b
b
b
b
⎵
5
个
  
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;
}