8.25重庆南开CSP信心赛

a 夏天 提交于 2019-11-28 13:13:02

 8.25重庆南开CSP信心赛

A.填数字

时间限制:1s
空间限制:128MB


题面描述
信竞队的同学们在一个N*N的方格矩阵上填数字。开始时,所有矩阵里的数字都
0。 同学们一共给 个子矩阵填了数字,每次填的数都是从 这区间中
选一个数字,然后给对应矩阵全部填上该数字。比如:
1步,选了一个子矩阵,将数字2填上:
2 2 2 0
2 2 2 0
2 2 2 0
0 0 0 0
2步,选了一个子矩阵,将数字7填上:
2 2 2 0
2 7 7 7
2 7 7 7
0 0 0 0
3步,选了一个子矩阵,将数字3填上:
2 2 3 0
2 7 3 7
2 7 7 7
按此规则填下去,直到1到 中每个数字都被使用过一次(每个数字只能被使用
一次)。 现在给出最终的矩阵,但同学们已忘记第一步是选的哪个数子来填的。
请你帮忙计算第1步填的数字可能是哪些?输出第一步填写可能的数字的个数。
输入格式
第一行,一个整数N 接下来一个N*N的数字矩阵,表示填写结束时,矩阵的样
子。


输出格式
一个整数,表示第一步填可能的数字个数。
样例输入1

4 2
2 3 0
2 7 3 7
2 7 7 7
0 0 0 0


样例输出1

14

样例输入2

4 0
0 0 0
0 1 1 0
0 1 1 0
0 0 0 0

样例输出2

15


数据范围与约定
对于40% 的数据,保证n<=50
对于 100%的数据,保证 n<=1000

考察点:二阶差分
对于每个数字统计出现的最上u,最下d,最左l,最右r的位置,然后就能框出一个矩形,把
(u,l)(d,r)为对角线的矩阵整体加1,表示有一个矩形在这个位置至少涂了一次 最后,如果
一个格子的值>1,说明有超过一个矩形在这里涂了数字,那么这个格子最终的数字一定不能
最先涂 剩下的就是能最先涂的数字。 特殊情况:n1且最终矩阵里除了0外只有一种数字,
那么这个数字肯定不能先涂,要从答案中扣除。

  1 //fread快读快写,快的一批    2     3 #include<stdio.h>    4 #include<bits/stdc++.h>    5 using namespace std;    6 inline char nc()    7 {    8     static char buf[100000],*p1=buf,*p2=buf;    9     return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;   10 }   11 inline int rd()   12 {   13     char ch=nc();   14     int sum=0;   15     while(!(ch>='0'&&ch<='9'))ch=nc();   16     while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();   17     return sum;   18 }   19 #define I_int int   20 char F[ 200 ] ;   21 inline void write( I_int x )   22 {   23     I_int tmp = x > 0 ? x : -x ;   24     if( x < 0 ) putchar( '-' ) ;   25     int cnt = 0 ;   26     while( tmp > 0 )   27     {   28         F[ cnt ++ ] = tmp % 10 + '0' ;   29         tmp /= 10 ;   30     }   31     while( cnt > 0 ) putchar( F[ -- cnt ] ) ;   32 }   33 #undef I_int   34 int a[1005][1005];   35 int cn[1005][1005],Cnt[1005][1005];   36 int x_min[1000005],x_max[1000005],y_min[1000005],y_max[1000005];   37 int s[1005][1005];   38 int cnt;   39 bool mark[1000005];   40 bool mark2[1000005];   41 int n;   42 int main()   43 {   44    45     int i,j,k;   46     n=rd();   47     for(i=1; i<=n*n; i++) x_min[i]=y_min[i]=1e9;   48     for(i=1; i<=n; i++)   49     {   50         for(j=1; j<=n; j++)   51         {   52             a[i][j]=rd();   53             if(a[i][j]!=0)   54             {   55                 x_min[a[i][j]]=min(x_min[a[i][j]],i);   56                 x_max[a[i][j]]=max(x_max[a[i][j]],i);   57                 y_min[a[i][j]]=min(y_min[a[i][j]],j);   58                 y_max[a[i][j]]=max(y_max[a[i][j]],j);   59                 if(!mark[a[i][j]])   60                 {   61                     cnt++;   62                     mark[a[i][j]]=true;   63                 }   64             }   65         }   66     }   67     if(cnt==0)   68     {   69         write(n*n);   70         return 0;   71     }   72     if(cnt==1)   73     {   74         write(n*n-1);   75         return 0;   76     }   77     for(i=1; i<=n*n; i++)   78     {   79         if(mark[i])   80         {   81             cn[x_min[i]][y_min[i]]+=1;   82             cn[x_max[i]+1][y_min[i]]-=1;   83             cn[x_min[i]][y_max[i]+1]-=1;   84             cn[x_max[i]+1][y_max[i]+1]+=1;   85         }   86     }   87     int tot=0;   88     for(i=1; i<=n; i++)   89     {   90         for(j=1; j<=n; j++)   91         {   92             Cnt[i][j]=cn[i][j]+Cnt[i-1][j]+Cnt[i][j-1]-Cnt[i-1][j-1];   93             if(Cnt[i][j]>1)   94             {   95                 if(mark2[a[i][j]]==false)   96                 {   97                     mark2[a[i][j]]=true;   98                     tot++;   99                 }  100             }  101         }  102     }  103     write(n*n-tot);  104 }

B.路径数

时间限制: 1s
空间限制: 512MB

题目描述
给出一个N个节点的树,节点编号1N,其中1号点为根。每个节点都有一个权
值。我们需要找出一条路径,要求该路径经过的节点权值总和等于L。同时要
求,该路径中不能有深度相同的节点。问,满足条件的路径有多少条?


输入格式
第一行是两个整数NL
第二行是N个正整数,第i个整数表i号节点的权值。
接下来的N-1行每行是2个整数xy,表示xy的父亲。


输出格式
一个整数,表示满足条件的路径方案数
样例输入1

3 3
1 2 3
1 2
1 3

样例输出1

2
数据规模
对于100%的数据N<=100000,所有权值以及S都不超过1000。 

 

 

 1 // luogu-judger-enable-o2   2 #include<stdio.h>   3 #include<bits/stdc++.h>   4 using namespace std;   5 struct node   6 {   7     int to;   8     int next;   9 }edge[1000000];  10 int num,head[100005];  11 int n,s;  12 long long ans;  13 int a[100005],fa[100005][21],w[100005][21];  14 inline void add(int x,int y)  15 {  16     edge[++num].to=y;  17     edge[num].next=head[x];  18     head[x]=num;  19 }  20 inline void dfs(int x,int dad)  21 {  22     fa[x][0]=dad;  23     w[x][0]=a[x];  24     for(int i=1;i<=20;i++)  25     {  26         fa[x][i]=fa[fa[x][i-1]][i-1];  27         w[x][i]=w[x][i-1]+w[fa[x][i-1]][i-1];  28     }  29     int p=x,len=s;  30     for(int i=20;i>=0;i--)  31     if(fa[p][i]&&w[p][i]<len)  32     {  33         len-=w[p][i];  34         p=fa[p][i];  35     }  36     if(len==w[p][0])ans++;  37     for(int i=head[x];i;i=edge[i].next)  38     if(edge[i].to!=dad)dfs(edge[i].to,x);  39 }  40 int main()  41 {  42     ios::sync_with_stdio(false);  43     cout.tie(NULL);  44     cin>>n>>s;  45     for(int i=1;i<=n;i++)  46     cin>>a[i];  47     int x,y;  48     for(int i=1;i<n;i++)  49     {  50         cin>>x>>y;  51         add(x,y);  52         add(y,x);  53     }  54     dfs(1,0);  55     cout<<ans;  56 }  57     

C旅店

时间限制 : - MS   空间限制 : - KB 

评测说明 : 1s,256m
问题描述

一条笔直的公路旁有N家旅店,从左往右编号1到N,其中第i家旅店的位置坐标为
旅人何老板总在赶路。他白天最多行走个单位的距离,并且夜间必须到旅店休息。
何老板给你Q个询问,每个询问的都由两个整数构成,其中第i个询问的格式为,,表示他想知道自己从号旅店走到号旅店,最少需要花费多少天?

输入格式

第一行,一个整数N

第二行,N个空格间隔的整数  表示每个旅店的坐标

第三行,一个整数L

第四行,一个整数Q

接下来Q行,每行两个整数,表示一次询问

输出格式

Q行,每行一个整数,依次表示对应询问的答案

样例输入

9
1 3 6 13 15 18 19 29 31
10
4
1 8
7 3
6 7
8 5

样例输出

4
2
1
2

提示

对于100%的数据:

2<=N<=10^5

1<=L<=10^9

1<=Q<=10^5

1<=X1<=X2...<=Xn<=10^9

X(i+1)-Xi<=L

Ai != Bi

 

 

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!