题意: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;}