8.25重庆南开CSP信心赛

 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

猜你喜欢

转载自www.cnblogs.com/CXYscxy/p/11408590.html