目录
A. Sorting with Twos
思路:
由于是以前缀的形式集体减去一个常数1,因此对于每个删除的节点之间,一定是同步删除的,所以想要最终实现一个不完全升序,那么就一定要保证最开始,两个节点之间是一个不完全升序,否则无论都无法达到最后的不完全上升数组。
代码如下:
#include<bitsdc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define PII pair<int,int>
const int N=1e6+10;
const int mod=1e9+7;
int arr[N];
void solve()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)cin>>arr[i];
int l=1,r=2;
while(l<=n)
{
for(int i=max(l,1ll)+1;i<=min(r,n)-1;i++)
{
if(arr[i]>arr[i+1])
{
cout<<"NO"<<endl;
return ;
}
}
l=r;
r=r*2;
}
cout<<"YES"<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
B、Deja Vu
思路:
数组a中每一个数,对于x中相同的任意个个数只会操作一次。
证明:假设是 的倍数,令
出现了一个 ,那么
可得ai变成 的倍数
而 中不包含因子 因此绝对不会再次和 再次发生操作关系。
由此可见,当 与某个数发生一次操作关系后,不会再次与这个数值发生操作关系
所以此题只需要将 x 数组按顺序去重即可
代码如下:
#include<bits×dc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define PII pair<int,int>
const int N=1e6+10;
const int mod=1e9+7;
int n,m;
int arr[N],book[100];
void solve()
{
memset(book,0,sizeof(book));
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>arr[i];
vector<int>ans;
for(int i=1;i<=m;i++)
{
int x;
cin>>x;
if(book[x]==0)ans.push_back(x);
book[x]=1;
}
for(auto i:ans)
{
int a=(1<<i);
int b=(1<<(i-1));
for(int j=1;j<=n;j++)
{
if(arr[j]%a==0)arr[j]+=b;
}
}
for(int i=1;i<=n;i++)cout<<arr[i]<<" ";
cout<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
C、Smilo and Monsters
思路:
贪心:记录最大的数为mx,从最小的数开始进行第一种操作,当x的值等于最大值mx时,直接将利用操作 2 将mx删除,
因此此题可以利用双端队列,
注意:当队列大小为1的时候要进行特判。当队列中剩余的个数为1时,要与与该情况衔接的情况进行判断。
代码如下:
#include<bits×dc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define PII pair<int,int>
const int N=1e6+10;
const int M=1e4+10;
void solve()
{
int n;
cin>>n;
vector<int>ans;
deque<int>aas;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
ans.push_back(x);
}
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();i++)
{
aas.push_back(ans[i]);
}
int sum=0;
int flag=0;
while(aas.size()-1&&aas.size())
{
int t=aas.front();
if(aas[(int)aas.size()-1]>t)
{
aas[(int)aas.size()-1]-=t;
sum+=t;
aas.pop_front();
if(aas.size()==1)flag=1;
}
else if(aas[(int)aas.size()-1]<t)
{
aas[0]-=aas[(int)aas.size()-1];
sum+=(aas.back()+1);
aas.pop_back();
}
else
{
sum+=(aas.front()+1);
aas.pop_front();
aas.pop_back();
}
}
if(aas.size()==1)
{
if(aas[0]==1)
{
if(flag==1)sum+=2;
else sum+=1;
}
else
{
if(aas[0]%2==0)sum+=(aas[0]/2+1);
else sum+=(aas[0]/2+2);
}
}
cout<<sum<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}
D、Suspicious logarithms
思路:
先盲猜g会按照x升序递增,打表后发现不对劲,g(x)函数中间可能会存在波动,
将每个区间l,r按照f(x)的值来进行拆分,对于每个分段,f(x)的值相等,
令t=f(x),对于每个分段,可以按照1……t,t……t*t,t*t……t*t*t,t*t*t……t*t*t*t来进行二次拆分,二次拆分后的每个分段中 g(x)的值相等,然后利用乘法计算和即可。
注意:此题中间的数据会爆long long,在第二次拆分时一定要对右边界的值进行特判。
代码如下:
#include<bits×dc++.h>
using namespace std;
#define int long long
#define endl "\n"
#define PII pair<int,int>
const int N=1e6+10;
const int mod=1e9+7;
void solve()
{
int L,R;
cin>>L>>R;
int sum=0;
for(int i=2;i<=61;i++)
{
int l=max(L,((int)1<<i));
int r=min(R,((int)1<<(i+1))-1);
if(l>r)continue;
int bg=1;
int ed=i;
int ssm=0;
while(bg<=r)
{
sum+=((min(ed-1,r)-max(bg,l)+1)>=0?(min(ed-1,r)-max(bg,l)+1):0)*ssm%mod;
bg=ed;
if(ed*i>r||ed*i<ed)ed=r+1;
else ed=ed*i;
ssm++;
}
}
cout<<sum%mod<<endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)solve();
return 0;
}