普及C组模拟赛5
1.【普组模拟赛】马农
题目描述
在观看完战马检阅之后,来自大草原的两兄弟决心成为超级“马农”,专门饲养战马。
兄弟两回到草原,将可以养马的区域,分为 N*N 的单位面积的正方形, 并实地进行考察,归纳出了每个单位面积可以养马所获得的收益。接下来就要开始规划他们各自的马场了。
首先,两人的马场都必须是矩形区域。同时,为了方便两人互相照应,也为了防止马匹互相走散,规定两个马场的矩形区域相邻,且只有一个交点。最后,互不认输的两人希望两个马场的收益相当,这样才不会影响他们兄弟的感情。
现在,兄弟两找到你这位设计师,希望你给他们设计马场,问共有多少种设计方案。
输入
第一行一个整数 N,表示整个草原的大小为 N*N。
接下来 N 行,每行 N 个整数 A(i,j),表示第 i 行第 j 列的单位草地的收成。
(注意:收益可能是负数,养马也不是包赚的,马匹也可能出现生病死亡等意外。)
输出
输出符合两人要求的草原分配方案数。
样例输入
3
1 2 3
4 5 6
7 8 9
样例输出
2
数据范围限制
【数据范围】
40%的数据, N<=10。
100%的数据, N<=50, -1000<A(i,j)<1000。
正解
前缀和+暴力判断
有两种情况
一种左上和右下
一种左下和右上
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
int n,s,a,b[1005][1005],c[10000005];
int main()
{
freopen("farmer.in","r",stdin);
freopen("farmer.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
cin>>a;
b[i][j]=b[i-1][j]+b[i][j-1]-b[i-1][j-1]+a;//二维前缀和
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
for(int x=1;x<=i;x++)//每个数字出现的次数加1
for(int y=1;y<=j;y++)
c[b[i][j]-b[x-1][j]-b[i][y-1]+b[x-1][y-1]]++;
for(int x=i+1;x<=n;x++)//如果这里也出现了,那就加这个数字出现的次数
for(int y=j+1;y<=n;y++)
if(c[b[x][y]-b[i][y]-b[x][j]+b[i][j]]!=0)
s+=c[b[x][y]-b[i][y]-b[x][j]+b[i][j]];
for(int x=1;x<=i;x++)//清零
for(int y=1;y<=j;y++)
c[b[i][j]-b[x-1][j]-b[i][y-1]+b[x-1][y-1]]=0;
for(int x=i+1;x<=n;x++)//下面同上
for(int y=1;y<=j;y++)
c[b[x][j]-b[i][j]-b[x][y-1]+b[i][y-1]]++;
for(int x=1;x<=i;x++)
for(int y=j+1;y<=n;y++)
if(c[b[i][y]-b[x-1][y]-b[i][j]+b[x-1][j]]!=0)
s+=c[b[i][y]-b[x-1][y]-b[i][j]+b[x-1][j]];
for(int x=i+1;x<=n;x++)
for(int y=1;y<=j;y++)
c[b[x][j]-b[i][j]-b[x][y-1]+b[i][y-1]]=0;
}
cout<<s;
return 0;
}
2.【普组模拟赛】马语翻译
题目描述
随着马场的繁荣,出现了越来越多的新马种。种族之间的沟通不畅严重影响了马场的和谐。这时,科学家发明了马语翻译机器人,正好可以解决这一难题。
机器人有 M 种,每种机器人能完成 K 个马种之间的语言翻译。问,利用这些机器人,能否实现 1 种群和 N 种群的马语翻译。 若可以,找到翻译过程至少需要用到多少种语言。
输入
第一行三个整数 N, K 和 M,分别表示语言数, 每个机器人能翻译的语言数, 机器人的数量。
接下来 M 行,每行 K 个整数。表示每个机器人可以翻译的语言编号(编号从 1 到 N)。
输出
输出最少转换语言的次数。如果无法完成翻译,输出-1。
样例输入
9 3 5
1 2 3
1 4 5
3 6 7
5 6 7
6 8 9
样例输出
4
【样例解释】
1-3-6-9 或者 1-5-6-9
数据范围限制
【数据范围】
40%的数据 N<=100, 1<=K<=20, M<=40。
100%的数据 1<=N<=100000, 1<=K<=1000, 1<=M<=1000。
正解
DP
AC代码
#include<iostream>
#include<cstdio>
using namespace std;
long long n,k,m,x,f[100005],a[1005][1005];
int main()
{
freopen("trans.in","r",stdin);
freopen("trans.out","w",stdout);
cin>>n>>k>>m;
for(int i=1;i<=m;i++)
for(int j=1;j<=k;j++)
cin>>a[i][j];
for(int i=2;i<=n;i++)//赋初值
f[i]=2147483647;
f[1]=1;
for(int o=1;o<=2;o++)//多次更新
for(int i=1;i<=m;i++)//dp
{
x=2147483647;//找到最小的翻译
for(int j=1;j<=k;j++)
x=min(x,f[a[i][j]]);
for(int j=1;j<=k;j++)//更新
f[a[i][j]]=min(f[a[i][j]],x+1);
}
if(f[n]==2147483647)cout<<-1;//可能翻译不了
else cout<<f[n];
return 0;
}
3.【普组模拟赛】马球比赛
题目描述
在解决了马语翻译问题后,马匹数量越来越多,不少乡镇都有了数量可观的马匹,开始出现马球比赛。乡镇之间决定进行马球联赛。
联赛的赛制,主要是比赛双方的马匹数量,成了一个急需解决的问题。首先,所有乡镇都要求,本乡镇所有的马匹都必须参赛,或者都不参赛(若组队的马匹数量不是该镇马匹数量的约数,将无法参赛)。其次,在本乡镇,选出最佳球队,参加乡镇间联赛。
现在,比赛组织方希望满足所有参赛乡镇的要求,并且使得决赛的马匹尽可能多,请你设计每个球队马匹的数量,使得决赛马匹数最大。注意,决赛至少有 2 个队伍晋级。
输入
第一行一个整数 N,表示想要报名参赛的乡镇。
接下来 N 个用空格分开的整数 a(i),表示第 i 个乡镇报名参赛的马匹数。
输出
计算出决赛最大参与的马匹数。
样例输入
【输入样例 1】
3 1 3 6
【输入样例 2】
5 4 6 3 8 9
样例输出
【输出样例 1】
6
【样例解释】 每个队伍 3 匹马,乡镇 1 无法参赛。乡镇 2 和 3 都可以进行比赛,决赛 2 个队伍,共 6匹马。
【输出样例 2】
9
【样例解释】 每个队伍 3 匹马,乡镇 2,3,5 可以参赛。决赛 3 个队伍, 9 匹马。
数据范围限制
【数据范围】
20%的数据 2<=N<=100, 1<=a(i)<=10000。
50%的数据 2<=N<=20000。
100%的数据 2<=N<=200000, 1<=a(i)<= 2000000。
正解
求出每个数能参赛乡村的个数
枚举一边即可
AC代码
#include<iostream>
#include<cmath>
#include<cstdio>
int n,a,m;
long long s,f[2000005];
using namespace std;
int main()
{
freopen("polo.in","r",stdin);
freopen("polo.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
f[a]++;//自己也是约数
m=max(a,m);
}
for(int i=2;i<=m;i++)
if(f[i]!=0)
for(int j=2;j*j<=i;j++)
if(i%j==0)
{
f[j]+=f[i];//加f[i]
if(j*j!=i)f[i/j]+=f[i];//不能重复加
}
s=n;
for(int i=2;i<=m;i++)//枚举,找最大
if(f[i]>=2)s=max(s,i*f[i]);//要大于等于2
printf("%lld",s);
return 0;
}
4.【普及模拟】数列
题目描述
给定一个长度为N的数列,求一段连续的子数列满足该子数列中的各元素的平均数大于A,输出可行方案的总数。
输入
第一行两个整数N,A
接下来N个整数,代表数列的N个元素。
输出
一个整数,即可行的方案数。
样例输入
5 1
1 2 3 4 5
样例输出
14
数据范围限制
数据规模
对于60%的数据 N <= 1000
对于100%的数据 N <= 100000
所有数据包括都在longint范围内。
正解
一种玄学的方法
AC代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct qq{
int sum,x;}a[200000];//结构体
bool dd(qq u,qq v){
return u.sum<v.sum||u.sum==v.sum&&u.x>v.x;}
long long b,c,d,e,f[200000];
int main()
{
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
cin>>b>>c;
for(register int i=1;i<=b;i++)
{
scanf("%lld",&a[i].sum);
a[i].sum+=a[i-1].sum-c;
a[i].x=i;
}
sort(a+1,a+b+1,dd);//快排
for(register int i=1;i<=b;i++)//下面是玄学
{
e=a[i].x-1;
while(e)d+=f[e],e-=(e&-e);
if(a[i].sum>0) d++;
e=a[i].x;
while(e<=b)f[e]++,e+=(e&-e);
}
cout<<d;
}
赛后总结
1.
用了大半天才AC
2.
开始用最短路40分,后来用dpAC
3.
没有看题,没时间,后来经过讲解才AC
4.
经过陈巨佬讲解,才知道AC