Codeforces Round 769 (Div. 2)(Dgcd st表+二分 or 分解因数 C 位运算分类讨论)
2023-12-14 18:59:32
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
int sum[1<<16];
void solve()
{
cin>>n;
string s;cin>>s;
if(s=="1"||s=="0"||s=="01"||s=="10"){
cout<<"YES\n";
}
else cout<<"NO\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
首先最大值肯定存在n里面最大的二进制的1的最高位
然后还有个结论是相邻的异或和最小,尽量是连续的数
所以直接在二进制的1的最高位的左边接个0断开就行了
其他连续就行
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
void solve()
{
cin>>n;
int mx=0;
for(int i=0;i<n;i++){
if((1<<i)<n){
mx=1<<i;
}
else break;
}
for(int i=1;i<mx;i++){
cout<<i<<" ";
}
cout<<"0 ";
for(int i=mx;i<n;i++) cout<<i<<" ";
cout<<"\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
操作题先想操作性质
第三个操作使得 (a|b)>=max(a,b)
这个时候操作a已经没用了,只能让b增加到(a|b)
所以分类讨论
1先加a 然后或运算 然后让b增加
2.b增加 然后或运算 然后让b增加
因为b总和<=1e6 所以直接枚举操作增加多少次即可
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
void solve()
{
int a,b;
cin>>a>>b;
int res=b-a;
for(int i=a;i<=a+b-a;i++)
{
if(i==b)
{
res=min(res,i-a);
}
else
{
res=min(res,1+i-a+(i|b)-b);
}
}
for(int i=b;i<=b+b-a;i++)
{
res=min(res,i-b+1+(i|a)-i);
}
cout<<res<<"\n";
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
cin>>t;
while(t--) solve();
}
D:
gcd没思路就从因子身上出发
首先有个共同的点是,如果当前端点存在和前面点构成不合法区间
怎么办
修改当前端点为一个很大质数这样前面gcd都是1
又因为区间长度大于1所以前面的区间都不用管
维护一个pre 表示1到pre的区间都不用管了
先讲因子思路
每个数最多有logn个因子
所以直接枚举每个因子的开始区间和结束区间,
然后暴力枚举每个因子是否存在不合法的情况即可
假设因子开始区间是 l 结束区间是r
当前点是 i,因子是x
不合法就是 i-y+1=x
y=i-x+1
如果y在l到r则不合法
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
int f[N][22];
int gcd(int a, int b) // 欧几里得算法
{
return b ? gcd(b, a % b) : a;
}
void init(){
for (int j = 0; j < 20; j ++ )
for (int i = 1; i + (1 << j)-1<=n; i ++ )
if (!j) f[i][j] = a[i];
else f[i][j] = gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
int query(int l,int r){
int len=r-l+1;
int k=log(len)/log(2);
return gcd(f[l][k],f[r-(1<<k)+1][k]);
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int res=0;
int pre=0;
vector<array<int,3>> st;
for(int i=1;i<=n;i++){
for(auto&t:st){
t[2]=gcd(t[2],a[i]);
}
st.push_back({i,i,a[i]});
vector<array<int,3>> f;
for(int j=0;j<st.size();j++){
if(f.empty()){
f.push_back(st[j]);
}
else if(f.back()[2]==st[j][2]){
f.back()[1]=st[j][1];
}else f.push_back(st[j]);
}
swap(f,st);
for(auto&t:st){
int at=i-t[2]+1;
if(t[0]<=at&&at<=t[1]){
if(at>pre){
res++;
pre=i;
}
}
}
cout<<res<<" ";
}
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
// cin>>t;
while(t--) solve();
}
第二思路:
因为gcd是单调递减
上面的式子
i-y+1=x
i+1=x+y
因为y和x都是递减的
所以越靠左x+y越小,但是i+1是定值
满足二分
所以用个二分+st表查询区间gcd即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+10,mod=998244353;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const long long inf=1e17;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
int f[N][22];
int gcd(int a, int b) // 欧几里得算法
{
return b ? gcd(b, a % b) : a;
}
void init(){
for (int j = 0; j < 20; j ++ )
for (int i = 1; i + (1 << j)-1<=n; i ++ )
if (!j) f[i][j] = a[i];
else f[i][j] = gcd(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
}
int query(int l,int r){
int len=r-l+1;
int k=log(len)/log(2);
return gcd(f[l][k],f[r-(1<<k)+1][k]);
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
init();
int pre=1;
int res=0;
for(int i=1;i<=n;i++){
if(a[i]==1) res++,pre=i+1;
else{
int l=pre,r=i;
while(l<r){
int mid=l+r>>1;
if(query(mid,i)>=i-mid+1) r=mid;
else l=mid+1;
}
if(query(l,i)==i-l+1){
res++;
pre=i+1;
}
}
cout<<res<<" ";
}
}
signed main()
{
cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
int t=1;
// cin>>t;
while(t--) solve();
}
文章来源:https://blog.csdn.net/qq_61657632/article/details/134928807
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!