2017.9.14 模拟考试 解题报告
哈呀呀呀!Markdown吗!题目粘贴就这样子了。
P75
竞赛时间:????年??月??日??:??-??:??
题目名称
名称 hao jian dan
输入 hao.in jian.in dan.in
输出 hao.out jian.out dan.out
每个测试点时限 1秒 2秒 2秒
内存限制 512MB 512MB 512MB
测试点数目 20 20 20
每个测试点分值 5 5 5
是否有部分分 无 无 无
题目类型 传统 传统 传统
注意事项(请务必仔细阅读):
【问题描述】
从 中找一些数乘起来使得答案是一个完全平方数,求这个完全平方数最大可能是多少。
【输入格式】
第一行一个数字 。
【输出格式】
一行一个整数代表答案对 取模之后的答案。
【样例输入】
7
【样例输出】
144
【样例解释】
但是塔外面有东西。
【数据规模与约定】
对于 的数据, 。
对于 的数据, 。
对于 的数据,。
对于 的数据,。
【问题描述】
有 个数,随机选择一段区间,如果这段区间的所有数的平均值在 中则你比较厉害。求你比较厉害的概率。
【输入格式】
第一行有三个数 ,含义如上描述。
接下来一行有 个数代表每一个数的值。
【输出格式】
输出一行一个分数 代表答案,其中 互质。如果答案为整数则直接输出该整数即可。
【样例输入1】
4 2 3
3 1 2 4
【样例输出1】
7/10
【样例输入2】
4 1 4
3 1 2 4
【样例输出2】
1
【样例解释】
塔外面有棵树。
【数据规模与约定】
对于 的数据,。
对于 的数据,。
对于 的数据, 。
【问题描述】
的方阵上有 棵葱,你要修一些栅栏把它们围起来。一个栅栏是一段沿着网格建造的封闭图形(即要围成一圈)。各个栅栏之间应该不相交、不重叠且互相不包含。如果你最多修 个栅栏,那么所有栅栏的长度之和最小是多少?
【输入格式】
第一行三个整数 。
接下来 行每行两个整数 代表某棵葱的位置。
【输出格式】
一行一个整数代表答案。
【样例输入1】
6 1 4
1 3
4 2
4 4
6 4
【样例输出1】
18
【样例输入2】
6 2 4
1 3
4 2
4 4
6 4
【样例输出2】
16
【样例解释】
你猜树上有啥。
【数据规模与约定】
对于 的数据, 。
对于 的数据, 。
对于 的数据, 。
对于 的数据, 。
三道题分别预计50+30+10=90 实测55+30+10=95
T1
质因数分解 反正找找规律不难发现 一个完全平方数乘以一个完全平方数一定还是一个完全平方数,好了那么久自认而然的想到质因数分解+快速幂。
首先筛出一些质数
求出每个质数用了几遍
计算答案,注意对于每一个素数只能去他的偶数次幂,既:假如质数3一共用了5次,那么他对答案的贡献只有3^4
有一点值得注意的是:50分做法和100分做法都是质因数分解+快速幂,100分做法在于能不能想到快速统计1-N的每个数字用了每个质数几遍
50统计方法:
inline void prepare(int x){
int j=0;
while(j<=5682&&x){
while(x%prime[j]==0) x/=prime[j],++mp[prime[j]];
++j;
}
}
for(i=2;i<=n;++i) prepare(i);
5682是我打表的素数,本来打了100W之内的,发现跑的太慢,有可能连50分都T,果断删掉
100分统计方法:
for(i=0;i<Num;++i){
int t=n;
while(t){
Sum[i]+=t/Prime[i];//这种计算每个质数用了几次的算法 很巧妙
t/=Prime[i];
}
}
Num是我们求出的素数的个数,Sum[i]表示第i个素数用了几次
这样就能100分了
T2:
要求 区间平均值>=l&&<=r 的个数
即
现在我们来求区间平均值在1~r的个数和1~l(不包括l)的个数 前减后即为所求
以求1~r为例
(a[i]+a[i+1]+……+a[i+k-1])/k<=r
(a[i]+a[i+1]+……+a[i+k-1])<=k*r
(a[i]+a[i+1]+……+a[i+k-1])-k*r<=0
(a[i]-r)+(a[i+1]-r)+……+(a[i+k-1]-r)<=0
令c[i]=a[i]-r得到一个新数组c
即求c数组区间和<=0的个数
令s为数组c的前缀和数组
c[i]+c[i+1]+…+c[i+k-1]<=0
s[i+k-1]-s[i]<=0
s[i+k-1]<=s[i]
则
i< i+k-1
s[i]>=s[i+k-1]
即求s数组逆序对数
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int MAXN = 500010;
LL n,l,r,ans1,ans2,a[MAXN],b1[MAXN],b2[MAXN],c[MAXN];
LL s1[MAXN],s2[MAXN];
#define lowbit(i) (i&(-i))
void Add(int x){
for(int i=x;i<=n;i+=lowbit(i)) ++c[i];
}
LL Get_Sum(int x){
LL ret=0;
for(int i=x;i>=1;i-=lowbit(i)) ret+=c[i];
return ret;
}
inline void read(LL &x){
x=0; int f=1; char c=getchar();
while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;
}
int main(){
freopen("jian.in","r",stdin);
freopen("jian.out","w",stdout);
read(n),read(l),read(r);
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1;i<=n;++i){
s1[i]=s1[i-1]+a[i]-l;
b1[i]=s1[i];
if(s1[i]<0) ++ans1;
s2[i]=s2[i-1]+a[i]-r;
b2[i]=s2[i];
if(s2[i]<=0) ++ans2;
}
sort(s1+1,s1+n+1);
sort(s2+1,s2+n+1);
LL t1=unique(s1+1,s1+n+1)-s1-1;
LL t2=unique(s2+1,s2+n+1)-s2-1;
for(int i=1;i<=n;++i){
LL pos=lower_bound(s1+1,s1+1+t1,b1[i])-s1;
b1[i]=pos;
pos=lower_bound(s2+1,s2+1+t2,b2[i])-s2;
b2[i]=pos;
}
for(int i=n;i>=1;--i){
ans1+=Get_Sum(b1[i]);
Add(b1[i]+1);
}
memset(c,0,sizeof c );
for(int i=n;i>=1;--i){
ans2+=Get_Sum(b2[i]);
Add(b2[i]);
}
LL up=ans2-ans1;
LL down = n*(n+1)/2;
if(up % down == 0 ) cout<<up/down<<endl;
else cout<<up/__gcd(up,down)<<'/'<<down/__gcd(up,down)<<endl;
fclose(stdin);fclose(stdout);
return 0;
}
T3
就是搜索
卡时也只能拿到95分,没啥好思路,有份题解没大看懂(那份能A)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<ctime>
#include<cstdlib>
using namespace std;
#define MAXN 25
#define INF 1000000000
int n,m,k,x[MAXN],y[MAXN],a[MAXN];
int mnx[MAXN],mny[MAXN],ans=INF,mxx[MAXN],mxy[MAXN];
void DFS(int t){
if(clock()>=1950){ printf("%d\n",ans); exit(0); }
if(t>n){
int sum=0;
for(int i=1;i<=k;++i)
if(a[i]) sum+=(mxx[i]-mnx[i]+mxy[i]-mny[i]+2)*2;
ans=min(ans,sum);
return ;
}
int sum=0;
for(int i=1;i<=k;++i)
if(a[i]) sum+=(mxx[i]-mnx[i]+mxy[i]-mny[i]+2)*2;
if(sum>=ans) return;
for(int i=1;i<=k;++i){
int pmnx=mnx[i],pmxx=mxx[i],pmny=mny[i],pmxy=mxy[i];
mnx[i]=min(mnx[i],x[t]);mxx[i]=max(mxx[i],x[t]);
mny[i]=min(mny[i],y[t]);mxy[i]=max(mxy[i],y[t]);
++a[i];
DFS(t+1);
mnx[i]=pmnx,mxx[i]=pmxx,mny[i]=pmny,mxy[i]=pmxy;
--a[i];
}
}
int main(){
freopen("dan.in","r",stdin);
freopen("dan.out","w",stdout);
memset(mnx,127/3,sizeof mnx );
memset(mny,127/3,sizeof mny );
scanf("%d%d%d",&m,&k,&n);
for(int i=1;i<=n;++i) scanf("%d%d",&x[i],&y[i]);
DFS(1);
printf("%d\n",ans);
fclose(stdin);fclose(stdout);
return 0;
}
总结:
T1
大约一个小时多一点,想到了,质因数分解,但是没想到到校的统计策略,50分。。。
T2
前缀和+暴力,先打了出来,后来在想怎么优化,但是没想出来,大约就一个小时左右吧
T3
知道应该就是搜索,
两个相交的矩形,肯定不如合成一个矩形更优,但是就是没思路写代码,只写了k==1的情况。。。
总的来说:
时间安排还凑活,搜索没打好。。