题意:T组数据,每组数据给你一个正整数 n,然后给你笛卡尔坐标系下n个矩形的左下角和右上角的点的坐标
(
x
i
1
,
y
i
1
)
,
(
x
i
2
,
y
i
2
)
(x_{i_1},y_{i_1}),(x_{i_2},y_{i_2})
(xi1,yi1),(xi2,yi2),保证矩形之间不会有重叠,求出所有的对称轴。
结论2:设所有矩形的端点中,横纵坐标的最小、最大值分别为
x
m
i
n
,
x
m
a
x
,
y
m
i
n
,
y
m
x
xmin, xmax, ymin, ymx
xmin,xmax,ymin,ymx,那么中心就是
(
x
m
i
n
+
x
m
a
x
)
/
2
,
(
y
m
i
n
+
y
m
a
x
)
/
2
(xmin + xmax) / 2, (ymin + ymax) / 2
(xmin+xmax)/2,(ymin+ymax)/2. 然后对称轴就是穿过这个中心的四条直线。
能留下的充要条件是最后只剩 01X,0X1,1X0,10X,X01,X10 这6种形式,即必须只剩一个0和一个1。我们发现,消除连续的三个0,会使0相对与1的数量差改变(001这种形式并不会改变0和1的数量差)。而我们可以通过一种方法算出最多消除几个0. 因为是N个数的排列,中位数是
(
N
+
1
)
/
2
(N + 1) / 2
(N+1)/2,因此到中位数的距离是
d
=
a
i
−
(
N
+
1
)
/
2
d = a_i - (N + 1) / 2
d=ai−(N+1)/2. d < 0 时,序列中0比较多,看看最多消掉的0的组数是否大于等于
∣
d
∣
|d|
∣d∣,如果是的话,那么这个数字就可以留下来。
#include<iostream>#include<algorithm>#include<cstring>usingnamespace std;constint maxn =5010;int a[maxn];char s[maxn];intcal(int l,int r,int i,bool is_small){int now =0, res =0;if(is_small){for(int j = l; j <= r; j++){if(a[j]> a[i]) now++;else now--;if(now ==3) res++, now =1;elseif(now ==-1) now =0;}}else{for(int j = l; j <= r; j++){if(a[j]< a[i]) now++;else now--;if(now ==3) res++, now =1;elseif(now ==-1) now =0;}}return res;}intmain(){int T;scanf("%d",&T);while(T--){int N;scanf("%d",&N);for(int i =1; i <= N; i++)scanf("%d",&a[i]);int mid =(N +1)/2;for(int i =1; i <= N; i++){bool is_small =true;if(a[i]> mid) is_small =false;if(cal(1, i -1, i, is_small)+cal(i +1, N, i, is_small)>=abs(a[i]- mid)) s[i]='1';else s[i]='0';}
s[N +1]=0;printf("%s\n", s +1);}return0;}
D. Junior Mathematician
感觉这个题又是一个dp的板子,有时候用大雪菜的方法并不好处理状态不含数位的情况。就比如这个,不含第 i 位数字是几的信息,因此没办法处理后面的步骤。
题意:求
[
L
,
R
]
(
R
≤
1
0
5000
)
[L,R] (R \le 10^{5000})
[L,R](R≤105000) 间满足
x
≡
f
(
x
)
m
o
d
m
(
m
≤
60
)
x \equiv f(x) \bmod m (m \le 60)
x≡f(x)modm(m≤60) 的数量。
d
p
(
i
,
s
u
m
,
r
e
s
)
dp(i, sum, res)
dp(i,sum,res):第
i
i
i 位,当前数字之和是
s
u
m
sum
sum,当前
f
(
x
)
−
x
f(x) - x
f(x)−x 为
r
e
s
res
res
这样子的话,我们用深搜去搜索答案。和大雪菜的思路差不多,从最高位开始搜,
d
f
s
dfs
dfs 中间那一大块儿,不同的数位
d
p
dp
dp 都是一样的。
#include<iostream>#include<algorithm>#include<cstring>#include<vector>typedeflonglong ll;const ll mod =1e9+7;usingnamespace std;constint maxn =5010;char s1[maxn], s2[maxn];int M;int f[maxn][60][60], p[maxn], a[maxn];intmy_mod(int a,int b){return(a % b + b)% b;}intdp(int pos,int sum,int res,bool limit){// lim=1 表示当前贴合上界,lim=0 则不贴合if(pos ==-1){return res ==0;}if(limit ==false&& f[pos][sum][res]!=-1){return f[pos][sum][res];}else{int ans =0, up = limit ? a[pos]:9;for(int i =0; i <= up; i++){int xx =my_mod(res + sum * i - i * p[pos], M);
ans =(ans +dp(pos -1,my_mod(sum + i, M), xx,(i == up)&& limit))% mod;}if(limit ==false){// 不贴合上界的情况有可能会被复用
f[pos][sum][res]= ans;}return ans;}}intsolve(char s[],int n){for(int i =0; i < n; i++){for(int j =0; j < M; j++){memset(f[i][j],-1,sizeof f[i][j]);}}for(int i =0; i < n; i++){
a[i]= s[n - i -1];}//这个方法也是从高数位往低数位填数字returndp(n -1,0,0,1);}intmain(){int T;scanf("%d",&T);while(T--){scanf("%s%s%d", s1, s2,&M);int n1 =strlen(s1), n2 =strlen(s2);for(int i =0; i < n1; i++) s1[i]-='0';for(int i =0; i < n2; i++) s2[i]-='0';
s1[n1 -1]--;for(int i = n1 -1; i >=0; i--){if(s1[i]<0){
s1[i]+=10;
s1[i -1]--;}elsebreak;}//for (int i = 0; i < n1; i++) printf("%d", s1[i]);
p[0]=1;for(int i =1; i < maxn; i++){
p[i]= p[i -1]*10% M;}//printf("*** %d %d\n", solve(s2, n2), solve(s1, n1));printf("%d\n",my_mod(solve(s2, n2)-solve(s1, n1), mod));}return0;}