【P1373】奶牛的卧室
看山神的题解写出来的,sro_dydxh_orz
原题:奶牛们有一个习惯,那就是根据自己的编号选择床号。如果一头奶牛编号是a,并且有0..k-1一共k张床,那么她就会选择a mod k号床作为她睡觉的地点。显然,2头牛不能睡在一张床上。那么给出一些奶牛的编号,请你为她们准备一间卧室,使得里面的床的个数最少。
n(1<=n<=5000),Si(1<=Si<=1000000)
题意就是对于任意一个num[i]<num[j],求一个m,使得num[i]%m!=num[j]%m
然后就可以把上面内个式子变一下:(num[i]-num[j])%m!=0
也就是任意一对大于0的差%m!=0
所以先给num排个序,答案在[n,num[n]]内
枚举答案验证,如果满足上面的条件,就输出
然而会T
怎么优化呐
用一个类似于筛法的方法,用一个flag记录那些差没有出现,然后预处理所有的差(一点需要注意的地方,因为排好序了所以j要枚举到<i)
然后枚举[n,num[n]],如果i没有出现,还不能直接说是答案,要枚举i的倍数,如果i的倍数出现过,依旧不能作为答案
为什么呐
设i的倍数是i*c且出现过,因为i*c出现过,所以可设i*c=num[p]-num[q],则(num[p]-num[q])%i = i*c%i = c != 0,就不满足上面的条件
山神在一开始的时候把1-(n-1)标记为出现过了,我觉得没有必要吧,因为枚举答案是从n-num[n]枚举的
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1; char ch=getchar(); 8 while(ch<'0'||ch>'9'){if(ch=='-')mark=-1; ch=getchar();} 9 while(ch>='0'&&ch<='9'){z=(z<<3)+(z<<1)+ch-'0'; ch=getchar();} 10 return z*mark; 11 } 12 int n,a[5100]; 13 bool flag[1100000]; 14 int main(){//freopen("ddd.in","r",stdin); 15 memset(flag,0,sizeof(flag)); 16 cin>>n; 17 for(int i=1;i<=n;i++){ a[i]=read(); flag[i]=true;} 18 flag[n]=false; 19 sort(a+1,a+n+1); 20 for(int i=1;i<=n;i++) 21 for(int j=1;j<i;j++) 22 if(!flag[a[i]-a[j]]) 23 flag[a[i]-a[j]]=true; 24 for(int i=n;i<=a[n];i++){ 25 if(!flag[i]) 26 for(int k=i*2;k<=a[n];k+=i)if(flag[k]){ flag[i]=true; break;} 27 if(!flag[i]){ cout<<i<<endl; return 0;} 28 } 29 cout<<a[n]<<endl; 30 return 0; 31 }