学者(scholar)
【题目描述】
翠江城有一位可敬的学者,这一天你跟随着小C去拜访他。然而在会客厅,小C却把你撂在一旁,自己跟学者谈笑风生。你难免会有些不满。学者也注意到了你,他决定给你一些事做。学者家里有n本书籍,从1~n标号,而且这些书籍都有一种奇妙的特性:如果两本书的标号的最大公因数大于1,那么这两本书就含有相关的内容。其中标号为质数的书籍为重要书籍。学者要求你从中找出一套包含至少一本重要书籍的互不相关的书籍。你听了头皮发麻,随手抽了k本互不相关的书籍,竟然满足了要求。你就很好奇,k最小是多少一定可以满足学者的需求呢?
【输入数据】
输入第一行一个正整数T,表示数据组数。
接下来T行,每行一个正整数n,表示学者家的藏书量。
【输出数据】
输出T行,每行一个整数,表示对于每个n,最小的k,对于无解的情况,输出-1。
【样例输入】
1
8
【样例输出】
3
【数据范围】
对于10%的数据,T,n<=5;
对于20%的数据,T,n<=1000;
对于50%的数据,n<=10^9;
另外20%的数据,T=1;
对于100%的数据,1<=T<=10^5,1<=n<=10^14。
【样例解释】
所有3元互不相关的书籍集合为:
{1,2,3},{1,2,5},{1,2,7},{1,3,4},{1,3,5},{1,3,7},{1,3,8},{1,4,5},
{1,4,7},{1,5,6},{1,5,7},{1,5,8},{1,6,7},{1,7,8},{2,3,5},{2,3,7},
{2,5,7},{3,4,5},{3,4,7},{3,5,7},{3,5,8},{3,7,8},{4,5,7},{5,6,7},
{5,7,8},其中每个集合都包含一本重要书籍。
题意:求最小的k满足1~n中任意k个互质的数组成的集合中都至少有一个质数,多次询问。
题解:为了求出最小k,我们要尽量构造1~n最大的不含质数的互质子集,显然把1和每个质数平方丢进去即可,所以我们只要求出sqrt(n)内质数个数x,x+2即为答案。先预处理出1~10^7内所有质数,二分查询质数即可。
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<cmath> 4 #define MN 10000000 5 using namespace std; 6 int T,ans,cnt,pr[664580]; 7 long long n; 8 bool vis[MN+5]; 9 void shai(){ 10 for(int i=2;i<=MN;i++) 11 if(!vis[i]){ 12 pr[++cnt]=i; 13 for(int j=2;j*i<=MN;j++) vis[i*j]=1; 14 } 15 } 16 int main(){ 17 freopen("scholar.in","r",stdin); 18 freopen("scholar.out","w",stdout); 19 scanf("%d",&T); shai(); 20 while(T--){ 21 scanf("%lld",&n); 22 if(n==1){printf("-1 ");continue;} 23 n=sqrt(n); 24 int l=0,r=664580,ans; 25 while(l<=r){ 26 int mid=(l+r)>>1; 27 if(pr[mid]<=n) l=mid+1,ans=mid; 28 if(pr[mid]>n) r=mid-1; 29 } 30 printf("%d ",ans+2); 31 } 32 return 0; 33 }
主持人(anchorman)
【题目描述】
小W是这次献祭的主持人。为了举行献祭,他先亲自去掀翻小C的棋盘,所以他就把布置场地的任务交给了你。有一片N行M列的网格土地,每一格都有一个XY值cij。你需要挑选出其中一块A行B列的土地作为献祭场地。我们定义一块土地的不稳定度为这块土地中最大的XY值和最小的XY值的差,为了保持均衡,要求挑选的场地的不稳定度尽可能小。小W希望你求出这个最小值,并统计有多少块场地满足这个最小值。
【输入数据】
第一行四个正整数N,M,A,B。
接下来N行,每行M个整数,表示一个XY值矩阵。
【输出数据】
输出一行两个整数,用空格隔开,表示选择的场地中最小的不稳定度和满足最小值的场地数。
【样例输入】
2 3 1 2
1 3 2
1 4 2
【样例输出】
1 1
【数据范围】
对于10%的数据,N,M<=10;
对于30%的数据,N,M<=100;
对于50%的数据,N,M<=500;
另外10%的数据,0<=cij<=1;
另外10%的数据,|cij|<=5;
对于100%的数据,1<=N,M,A,B<=1000,A<=N,B<=M,
|cij|<=10^9。
【样例解释】
选择土地(1,2)~(1,3),最大为3,最小为2,相差为1。
题解(暴力):我们可以想到如果强行枚举n,m,A,B的话,复杂度为O(n^4),那么,如果我们先预处理出横向的情况并缩点,然后在枚举纵向的,2次的复杂度都为O(n^3/8)。似乎有90分。
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define MN 1005 5 using namespace std; 6 int n,m,A,B,a[MN][MN],b[MN][MN],c[MN][MN],ans=1e9,cnt; 7 int main() 8 { 9 freopen("anchorman.in","r",stdin); 10 freopen("anchorman.out","w",stdout); 11 scanf("%d%d%d%d",&n,&m,&A,&B); 12 for(int i=1;i<=n;i++) 13 for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); 14 memset(b,127,sizeof(b));memset(c,0,sizeof(c)); 15 for(int i=1;i<=n;i++) 16 for(int j=1;j<=m-B+1;j++) 17 for(int k=j;k<=j+B-1;k++){ 18 b[i][j]=min(b[i][j],a[i][k]); 19 c[i][j]=max(c[i][j],a[i][k]); 20 } 21 for(int j=1;j<=m-B+1;j++) 22 for(int i=1;i<=n-A+1;i++){ 23 int maxn=0,minn=1e9; 24 for(int k=i;k<=i+A-1;k++){ 25 minn=min(minn,b[k][j]); 26 maxn=max(maxn,c[k][j]); 27 } 28 ans=min(ans,maxn-minn); 29 } 30 for(int j=1;j<=m-B+1;j++) 31 for(int i=1;i<=n-A+1;i++){ 32 int maxn=0,minn=1e9; 33 for(int k=i;k<=i+A-1;k++){ 34 minn=min(minn,b[k][j]); 35 maxn=max(maxn,c[k][j]); 36 } 37 if(maxn-minn==ans) cnt++; 38 } 39 printf("%d %d",ans,cnt); 40 return 0; 41 }
邻居(neighbor)
【题目描述】
你最近刚刚搬进翠湖旁的一条街道里居住,于是希望认识一下四周的邻居。你了解到,这条街上的住民共有n户,自西向东一字排列。
你发现与其他街道不同的是,这条街上的所有住民将被分为AB两组,两组轮流定期对翠湖的水质进行检测并上报。为了保证每次检测的准确性,环境部门规定这条街上的住户,对于任意的一段,在其中A组住户和B组住户的数目之差不超过p,而且A组住户和B组住户的数目都是确定的。你很关心你会被分到哪一组,所以你希望知道住户分组的方案数。
【输入数据】
输入只有一行,四个正整数n,A,B,p,分别表示住户总数、A组住户数、B组住户数和题干中所述常数p。
【输出数据】
输出只有一行,表示住户分组的方案数,答案对10^9+7取模。
【样例输入】
5 2 3 1
【样例输出】
1
【数据范围】
对于20%的数据,A,B,p<=10;
对于40%的数据,A,B<=50;
另外20%的数据,p=1。
对于100%的数据,1<=A,B<=150,1<=p<=20,n=A+B。
【样例解释】
只有一种分组方案BABAB。