D 牛牛与整除分块
题意
给n,m两个数字,求n / m在n / i(i属于1~n)里面的整数从大到小排第几位
比如 n=25 ,m=9 ,(25,12,8,6,5,4,3,2,1)答案是 8
思路
因为整除分块有一个对称性,两两相乘接近n,1~sqrt(n)-1是都有的,但sqrt(n)*(sqrt(n)+1)>=n的时候整除分块是偶数个,其他时候是奇数个
比如20 sqrt(20)=4, 1 2 3 都有,按照对称性20,10,6,特判一下4*5==20,所以有两个数4和5
比如19 sqrt(19)=4, 1 2 3 都有,按照对称性20,10,6,特判一下4*5>19,所以只有一个4
#include<bits/stdc++.h>
#define endl '
'
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
const double pi = acos(-1);
using namespace std;
const int N = 1e5+10;
const int modd=1e9;
int main(){
int t;
scanf("%d",&t);
while(t--){
int n,x;
scanf("%d%d",&n,&x);
int k=(int)sqrt(n);
int ge=2*k-1;
if(k*k+k<=n){
ge++;
}
if(x<k){
printf("%d
",x);
}
else{
printf("%d
",ge-n/x+1);
}
}
return 0;
}
H 牛牛与交换排序
题意
牛牛有一个数组,数组元素是1到n的排列,即数组的值在1~n范围内,且每个数字仅出现1次。
牛牛想要将该数组变为升序排列的,他可以进行如下的操作。
首先他要确定一个长度k,k的范围在1~n之间。
接下来他将会进行若干次操作。在每轮操作中他都可以选择一段长度为k的子数组,然后进行区间的翻转操作。
他可以做任意次数的操作,但是要求他每次选择的子数组区间满足,并且区间长度等于一开始选定的k,也就是说一旦某一次操作选择了数组的某个位置进行区间翻转操作,下一次做区间翻转的位置将会比上一次更靠右。
牛牛发现,并不总是存在一个k可以使得数组排序变为有序,请你告诉牛牛是否存在一个k能够在满足规则的情况下完成排序。
思路
数组从头开始,第一个下标和值不相等,值当前的下标-下标=k,然后如果不行则no,直接用reverse(比赛的时候死磕j,看到这题时候去吃饭了……)
#include<bits/stdc++.h>
#define endl '
'
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
const double pi = acos(-1);
using namespace std;
const int N = 1e5+10;
const int modd=1e9;
int a[N];
int b[N];
int main(){
IOS;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];b[a[i]]=i;
}
int flag=0;
int len=0;
for(int i=1;i<=n;i++){
if(a[i]!=i){
if(len==0){
len=b[i]-i;
reverse(a+i,a+i+len+1);
}
else{
if(a[i+len]==i){
reverse(a+i,a+i+len+1);
continue;
}
else{
flag=1;
break;
}
}
}
}
if(flag==1)
cout<<"no"<<endl;
else{
cout<<"yes"<<endl;
cout<<len+1<<endl;
}
return 0;
}
I 牛牛的“质因数”
题意
求和,求一个函数f[i],i范围1~n的和,f[i]这个函数,举个例子1500=22355*5,F(1500)=223555。因子从小到大排序
思路
我想了一个线性筛的方法,但因为范围可能到10^20次,所以开了int128,每次线性筛里面每个数遇到最多一次,素数不遇到,所以f[素数]=素数,那么f[非素数]=f[非素数] * 10^位数 + f[素数]
#include<bits/stdc++.h>
#define endl '
'
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
const double pi = acos(-1);
using namespace std;
const int N = 4e6+10;
const ll modd=1e10;
int pri[N],a[N],tot=0,len[N];
void print(__int128 x) {
if (!x) return;
if (x < 0) putchar('-'), x = -x;
print(x / 10);
putchar(x % 10 + '0');
}
ll zhi[N];
void init(){
for(int i=2;i<N;i++){
if(!a[i]){
pri[tot++]=i;
zhi[i]=(ll)i;
}
ll cnt=1,k=zhi[i];
while(k){
cnt*=10;k/=10;
}
for(int j=0;j<tot&&i*pri[j]<N;j++) {
a[i*pri[j]]=1;
zhi[i*pri[j]]=zhi[pri[j]]*cnt+zhi[i];zhi[i*pri[j]]%=modd;
if(i%pri[j]==0){
break;
}
}
}
}
int main(){
init();
int n;
scanf("%d",&n);
ll sum=0;//cout<<(zhi[2097152])<<endl;
for(int i=2;i<=n;i++){
sum+=zhi[i];sum%=mod;
}
printf("%lld
",sum);
return 0;
}
J 牛牛想要成为hacker
题意
给了一个暴力求这个数组能不能有三角形组成,出个hack的数据,要求循环min(C(3,n),n * n * lg(n))
思路
第一想法前面斐波那契数列,然后比赛直接挂机了……C(3,n)是骗人的,其实只要斐波那契倒着来后面全是1即可
#include<bits/stdc++.h>
#define endl '
'
#define IOS ios::sync_with_stdio(false),cin.tie(0)
#define mem(a,b) memset(a,b,sizeof a)
#define pii pair<int,int>
#define ll long long
#define mod 1000000007
const double pi = acos(-1);
using namespace std;
const int N = 1e5+10;
const int modd=1e9;
int f[N];
int main(){
f[1]=2;f[2]=3;
int n;
for(int i=3;i<=40;i++){
f[i]=f[i-1]+f[i-2];
}
for(int i=41;i<N;i++){
f[i]=1;
}
scanf("%d",&n);
for(int i=1;i<=n;i++){
printf(i==n?"%d
":"%d ",f[i]);
}
return 0;
}