Advertisement

2015安徽省青少年信息学奥林匹克(AHOI)初中组

阅读量:

2015AHOI初中-T1- 猜谜游戏 [unique]

题目描述

滨湖幼儿园的老师带着N位小朋友在玩游戏。

他们玩的是猜谜游戏,在每一轮游戏中,每一位小朋友都需要给出一个在1到100之间的整数(包括1和100)。对于每一位小朋友来说,如果他给出来的数字式唯一的,或者说没有别的小朋友给出来相同的数字,则他就可以获得与所选数字相同的得分,否则得零分。

现在他们一共进行了三轮游戏。老师希望知道三轮游戏之后,每一位小朋友分别可以得到多少分数。

输入格式

输入有1+N行。

其中第一行给出一个正整数N(2≤N2≤200)表示参与游戏的小朋友有多少位。

之后N行中的第i行(1≤i≤N)给出三个大于等于1小于等于100的正整数。

分别表示第i位小朋友三轮游戏中分别给出的数字是多少。

输出格式

输出有N行。其中第i行(1≤i≤N)给出了第i个小朋友在经过了三轮游戏之后,可以合计得到的分数。

输入输出样例

输入样例1:
复制代码
输出样例1:
复制代码
输入样例2:
复制代码
输出样例2:
复制代码

说明

数据规模:

对于40%的数据,满足N <= 50

对于100%数据,满足N <= 200"

提示说明

对于样例一来说,假设五位小朋友分别名为Anold,Borel,Cayler,David和Einstein,则每一个人三轮游戏之后的得分情况如下所示:

Anold : 0 + 0 + 0 = 0

Borel : 0 + 0 + 92 = 92

Cayler : 63 + 89 + 63 = 215

David : 99 + 0 + 99 = 198

Einstein : 89 + 0 + 0 = 89

耗时限制1000ms 内存限制64MB

解析

考点:数组标记

参考代码

复制代码
 #include <bits/stdc++.h>

    
 using namespace std;
    
 const int N = 2e2+5;
    
 int n, a[N][3], f[N], s[N];
    
 int main(){
    
     cin >> n;
    
     for(int i = 1; i <= n; i++) {
    
     for(int j = 0; j < 3; j++) {
    
         cin >> a[i][j];            
    
     }
    
     }
    
     for(int j = 0; j < 3; j++) {
    
     memset(f, 0, sizeof f);
    
     for(int i = 1; i <= n; i++) {
    
         f[a[i][j]]++;
    
     }
    
     for(int i = 1; i <= n; i++) {
    
         if(f[a[i][j]] == 1)
    
             s[i] += a[i][j];
    
     }
    
     }
    
     for(int i = 1; i <= n; i++)
    
     cout << s[i] << '\n';
    
     return 0;
    
 }
    
    
    
    

2015AHOI初中-T2- 小岛 [islet] P2683

题目描述

西伯利亚北部的寒地,坐落着由N个小岛组成的岛屿群,我们把这些小岛依次编号为1到N。

起初,岛屿之间没有人和航线,后来随着交通的发展,逐渐出现了一些联通两座小岛的航线。例如增加一条在u号小岛与v号小岛之间的航线,这条航线的用时为e。那么沿着这条航线,u号小岛上的人可以前往v号小岛,同样的v号小岛上的人也可以前往u号小岛,其中沿着这一条航线花费的时间为e。

同时,随着旅游业的发展,越来越多的人前来游玩。那么两个小岛之间的最短路径是多少便成为了饱受关注的话题。

输入格式

输入文件islt.in共M+1行。

第一行有两个整数N和M,分别表示小岛的数和总操作数。

接下来的M行,每行表示一个操作,格式如下:

0 s t:表示询问从s号小岛到t号小岛的最短用时(1≤s≤n,1≤t≤n,s≠t)。

1 u v e:表示新增了一条从u号小岛到v号小岛,用时为e的双向航线(1≤u≤n,1≤v≤n,u≠v,1≤e≤10^5)

输出格式

输出文件islet.out针对每一次询问,单独输出一行。对于每一组询问来说,如果不存在可行的道路,则输出-1,否则输出最短用时。

输入输出样例

输入样例1:
复制代码
输出样例1:
复制代码
输入样例2:
复制代码
输出样例2:
复制代码

说明

数据规模

对于20%的数据,N ≤ 5且M ≤ 30。

对于40%的数据,N ≤ 20且M ≤ 200。

对于60%的数据,N ≤ 80且M ≤ 500。

对于80%的数据,N ≤ 100且M ≤ 2500。

对于100%的数据,N ≤ 100且M ≤ 5000。

耗时限制1000ms 内存限制64MB

解析

考点:图论,最短路,最小生成树

思路:

本题正解Floyed,考虑一次修改边的操作,将受到这条边影响的点枚举出来。(这条边相当于枚举中的K)。 有以下修改最短路的方式:

f[i][j]=f[i][s]+f[s][t]+f[t][j]

其中 f[s][t]表示刚刚读入的进行修改的边

对每次读入最新修改的边枚举 i,j更新最短路这样做 m 次就完了。

时间复杂度O((n^2)*m)

参考代码

复制代码
 #include<cstdio>

    
 const int inf=199999990;
    
 int n,m,f[101][101];
    
 int main(){
    
     int a,s,t,e;
    
     scanf("%d%d",&n,&m);
    
     for(int i=1;i<=n;i++){
    
     for(int j=1;j<=n;j++){
    
         if(i!=j)f[i][j]=inf;
    
     }
    
     }
    
     for(int i=1;i<=m;i++){
    
     scanf("%d%d%d",&a,&s,&t);
    
     if(a==0){
    
         if(f[s][t]!=inf)printf("%d\n",f[s][t]);
    
         else printf("-1\n");
    
     }
    
     else{
    
         scanf("%d",&e);
    
         if(e<f[t][s]){
    
             f[t][s]=f[s][t]=e;
    
             for(int k=1;k<=n;k++){
    
                 for(int l=1;l<=n;l++){
    
                     if(f[k][s]+f[s][t]+f[t][l]<f[k][l])
    
                         f[k][l]=f[l][k]=f[k][s]+f[s][t]+f[t][l];//核心语句更新f[k][l]的最短路 
    
                 }
    
             }
    
         }
    
     }
    
     }
    
     return 0;
    
 }
    
    
    
    

2015AHOI初中-T3- 上学路上 [school]

题目描述

小雪与小可可吵架了,他们决定以后互相再也不理对方了。尤其是,他们希望以后上学的路上不会再相遇。

我们将他们所在城市的道路网视作无限大的正交网络格,每一个整点数(x,y)对应了一个路口,相邻两个整数点之间有一条平行于x轴或平行于y轴的道路,其道路长度为1.已经知道小雪家住在(x1,0)处的路口附近,小可可的家住在(x2,0)处的路口附近。另外我们还知道,小学的学校在(0,y1)处的路口附近,小可可的学校在(0,y2)处的路口附近。其中保证x1<x2,且y1<y2。

因为上学不能迟到,所以小雪和小可可总是希望可以走最短路径去上学。同时为了避免见面,希望他们所选择的路线可以没有交点。

输入格式

输入文件的第一行输入四个正整数,依次为x1,x2,y1,y2,满足x1<x2,且y1<y2。

输出格式

在输出文件中,输出一个非负整数,表示可行方案的总数ans关于常数10^9+7取余后的值。

输入输出样例

输入样例1:
复制代码
输出样例1:
复制代码
输入样例2:
复制代码
输出样例2:
复制代码
输入样例3:
复制代码
输出样例3:
复制代码

说明

数据规模:

对于30%的数据,0<x1,x2,y1,y2≤500。

对于70%的数据,0<x1,x2,y1,y2≤3000。

对于100%的数据,0<x1,x2,y1,y2≤100000。

提示说明:

对于样例一来说,一共有三种可行方案,如下图所示。

耗时限制1000ms 内存限制64MB

解析:

考点:组合数学,容斥原理,计数原理

本题考虑用容斥的思想。先求出没有限制的总方案数,然后求出有路径相交的方案数,再相减即可。

参考代码:

复制代码
 #include<cstdio>

    
 #include<algorithm>
    
 #include<iostream>
    
 #include<cstring>
    
 #define ll long long
    
 #define mod 1000000007
    
 using namespace std;
    
 int x1,x2,y1,y2,fac[200005];
    
 void pre(){
    
     fac[1]=1;
    
     for(int i=2;i<=y2+x2+10;i++)
    
     fac[i]=1ll*fac[i-1]*i%mod;
    
 }
    
  
    
 int mul(int a,int b){
    
     int ans=1;
    
     while(b){
    
     if(b&1)ans=1ll*ans*a%mod;
    
     a=1ll*a*a%mod;b>>=1;
    
     }
    
     return ans;
    
 }
    
  
    
 int calc(int x,int y){
    
     int ans=1ll*fac[x+y]*mul(fac[x],mod-2)%mod;
    
     ans=1ll*ans*mul(fac[y],mod-2)%mod;
    
     return ans;
    
 }
    
  
    
 int main(){
    
     scanf("%d%d%d%d",&x1,&x2,&y1,&y2);pre();
    
     int t1=1ll*calc(x1,y1)*calc(x2,y2)%mod;
    
     int t2=1ll*calc(x1,y2)*calc(x2,y1)%mod;
    
     printf("%d",(t1-t2+mod)%mod);
    
     return 0;
    
 }
    
    
    
    

2015AHOI初中-T4- 琵琶湖 [lakebiwa]

题目描述

滋贺县的琵琶湖享有盛名,尤其是湖中央的琵琶岛。

琵琶岛不仅是外观上是矩形的,而且还被分割为了nxm的格子图。每一块格子区域都有着确定的高度。不幸的是,琵琶湖的水位最近开始上涨了,第i年湖面的高度将上涨至i米。另外一方面,琵琶岛是有松软的土质形成的,且琵琶湖的湖水可以自由渗入到其中。也就是说,如果有一块格子区域的高度不超过当前的水位,则将被淹没。相连的未被淹没的个字(有这公共边的格子区域)将组成一块未被淹没的区域。

现在,小可可希望知道对于制定某一年来说,琵琶岛被分割为了多少块未被淹没的区域。

输入格式

输入文件的第一行有两个整数n和m,由一个空格隔开,表示琵琶岛的大小。

之后n行,每行有m个正整数,在[1,10^9]范围内,表示了对应格子区域的高度。

之后一行有一个整数T.再之后的一行,有T个整数tj,满足0≤t1≤t2≤...≤tT-1≤tT≤10^9

输出格式

在输出文件中,你的程序应该输出单独一行,包含T个整数rj以空格隔开。其中rj表示了再第tj年,未被淹没的区域的个数。

输入输出样例

输入样例1:
复制代码
输出样例1:
复制代码

说明

对于20的数据,1 ≤ n ≤ 100, 1 ≤ m ≤ 100, 1 ≤ T ≤ 2000

有20%的数据,n = 1, 1 ≤ m ≤ 1000, 1 ≤ T ≤ 10 ^5

还有20%的数据,n = 2, 1 ≤ m ≤ 1000, 1 ≤ T ≤ 10^5

对于100%的数据,1 ≤ n ≤ 1000, 1 ≤ m ≤ 1000, 1 ≤ T ≤ 10^5

解析:

考点:并查集

参考代码:

复制代码
 #include <bits/stdc++.h>

    
 using namespace std;
    
 const int N = 1e5+5, M = 1e3+5;
    
 int n, m, T, t[N], flag[M][M], res[M*M];
    
 int fa[M*M], siz[M*M];
    
 struct P{
    
     int x, y, h;
    
     bool operator<(const P& rhs) const {
    
     return h > rhs.h;
    
     }
    
 } a[M*M];
    
 int dx[4] = {0,0,-1,1};
    
 int dy[4] = {-1,1,0,0};
    
  
    
 int find(int x) {
    
     if(fa[x] == x) return x;
    
     return fa[x] = find(fa[x]);
    
 }
    
  
    
 void merge(int x, int y) {
    
     x = find(x);
    
     y = find(y);
    
     if(siz[x] < siz[y]) swap(x, y);
    
     fa[y] = x;
    
     siz[x] += siz[y];
    
 }
    
  
    
 int main(){
    
     ios::sync_with_stdio(0);
    
     cin.tie(0);
    
     cin >> n >> m;
    
     int tmp;
    
     for(int i = 1; i <= n; i++) {
    
     for(int j = 1; j <= m; j++) {
    
         cin >> tmp;
    
         int t = (i-1)*m+j;
    
         a[t] = {i,j,tmp};
    
         fa[t] = t;
    
         siz[t] = 1;
    
     }
    
     }
    
     sort(a+1, a+n*m+1);
    
     cin >> T;
    
     for(int i = 1; i <= T; i++) cin >> t[i];
    
     int now = 1, ans = 0;
    
     for(int i = T; i >= 1; i--) {  // 倒序枚举
    
     while(now <= n*m &&a[now].h > t[i]) {
    
         ans++;
    
         int cx = a[now].x, cy = a[now].y;
    
         flag[cx][cy] = 1;
    
         for(int j = 0; j < 4; j++) {
    
             int nx = cx + dx[j], ny = cy+dy[j];
    
             if(nx<1||nx>n||ny<1||ny>m||!flag[nx][ny])
    
                 continue;
    
             int p1 = (nx-1)*m+ny, p2 = (cx-1)*m+cy;
    
             if(find(p1)!=find(p2)) {  // 两个区域相邻,可以合并
    
                 merge(p1, p2);
    
                 ans--;
    
             }
    
         }
    
         now++;
    
     }
    
     res[i] = ans;
    
     }
    
     for(int i = 1; i <= T; i++)
    
     cout << res[i] << ' ';
    
     return 0;
    
 }
    
    
    
    

全部评论 (0)

还没有任何评论哟~