day49 作业 Constuctive Problems

CF1537F Figure Fixing

首先我们可以特判要是st-sw是奇数的都是不合法的 因为我们对一条边+-都是偶数的变化

然后我们手画一个链 好像要是连通的话 值是可以传递的比如说该节点+2 我们可以任选一个节点+2

然后我们画一个环来看看 偶环 好的是和链一样的

奇环 我超 居然可以让任意点随意加2的倍数

结合上面的可以链的性质 要是我们图里有奇环 那就可以为所欲为了

要是没有咋办 我们想一下没有奇环 就是一个二分图 我们把二分图画出来 

找一下两边值的规律即可

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int h[N],e[N<<1],ne[N<<1],idx,w[N],t[N],n,m,f[N];
bool ans;
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs(int u){
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(!f[j]){
            f[j]=3-f[u];
            dfs(j);
        }else if(f[j]==f[u])ans=false;
    }
}
signed main(){
    fast
    int tt;cin>>tt;
    while(tt--){
        cin>>n>>m;
        memset(h,-1,sizeof h);
        memset(f,0,sizeof f);
        idx=0;
        int sw=0,st=0;
        for(int i=1;i<=n;i++)cin>>w[i],sw+=w[i];
        for(int i=1;i<=n;i++)cin>>t[i],st+=t[i];
        for(int i=1;i<=m;i++){
            int a,b;cin>>a>>b;
            add(a,b),add(b,a);
        }
        if(abs(st-sw)%2){
            cout<<"NO"<<endl;
            continue;
        }
        f[1]=1;
        ans=true;
        dfs(1);
        if(!ans){
            cout<<"Yes"<<endl;
        }else{
            int t1=0,t2=0;
            for(int i=1;i<=n;i++) if(f[i]==1) t1+=t[i]-w[i];else t2+=t[i]-w[i];
            if(t1==t2) cout<<"YES\n";
            else cout<<"NO\n";
        }
    }
    return ~~(0^_^0);
}

CF1458A Row GCD

这道题 我们需要知道一个

gcd(x,y) = gcd(y,x-y)

令人熟知的还有gcd(x,y)=gcd(y,x%y) gcd(n,n-1)=1

让后这个b题给的是

gcd(a1+bj,…,an+bj)

这样我们就可以变换一下把b消掉

gcd(a1+bj,a2-a1,a3-a1....an-a1)

处理出g=gcd(后面一坨)

然后对于每个bj 求一遍就可以了

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int a[N],b[N];
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}
signed main(){
    fast
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=m;i++)cin>>b[i];
    sort(a+1,a+n+1);
    int g=0;
    for(int i=1;i<=n;i++){
        g=gcd(g,a[i]-a[1]);
    }
    for(int i=1;i<=m;i++){
        cout<<gcd(a[1]+b[i],g)<<' ';
    }
    return ~~(0^_^0);
}

CF1254B2 Send Boxes to Alice (Hard Version)

很容易想到暴力来枚举k 看他每个的差值

但是很可能不合法 那我们可以把他sum加起来 枚举他的因子 这样是完全合法的

这里我们可以想到前缀和 

这样我们向前向后移动的话只有一个si 在变 (算是一个小技巧把

要是我们考虑ai 那么ai如何变成合法的 就和ai+1发生了联系

反正就是影响了ai+1 让后面计算不确定了

(Wow, now each moving steps only affect one number.)

要是ai满足每个k整除 那我们si也必须满足

这样我们就可以枚举每个k 看si的min了

但是min咋求 我们考虑一个贪心 我们现在要解决第一个点

我们只有从第一个点移开s1%k个 

或者从第二点拿过来 k-s1%k 个 这样我们第一个点就算成了 

就这样顺次向后推就可以了

如何证明其正确性呢 

感性证明:对于每一个 a[i],显然处理完它与 a[i+1] 之间的关系后它对后面的数就无法造成影响

了,所以我们对每一个a[i] 都贪心取到可以取的最小值并将影响累加给a[i+1] 的策略是正确的。

然后就是我们的k还可以简化一下 

要是我们 k1|sum k2|sum 那我们就不用取 k1k2|sum 可以想出来一定是不如他们的

还有就是这个时间复杂度的问题

一个数的质因子的因该是log(s) 但是我们可以枚举到20位左右

2*3*5....>10^12 所以最多是 O(20*n)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int a[N],n,s[N];
int cal(int x){
    int res=0;
    for(int i=1;i<=n;i++){
        res+=min(s[i]%x,x-s[i]%x);
    }
    return res;
}
signed main(){
    fast
    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i],s[i]=s[i-1]+a[i];
    if(s[n]==1){
        cout<<-1<<endl;
        return 0;
    }
    int cnt=s[n],ans=inf;
    for(int i=2;i*i<=s[n];i++){ //分解质因数的时候就判断了合法性了
        if(cnt%i==0) {
            while (cnt % i == 0)cnt /= i;
            ans = min(ans, cal(i));
        }
    }
    if(cnt>1)ans=min(ans,cal(cnt));
    cout<<ans<<endl;
    return ~~(0^_^0);
}

CF741C Arpa’s overnight party and Mehrdad’s silent entering

有点理解构造题的意思了

一时间能想到的有一些找不到了。牢记树是二部图。碰到能转成奇环的题稍微注意一下就行了。

 我们要找到一组合法解

首先我们要每对情侣吃的不一样 并且每三个人吃得都不一样

首先我们可以想到的是染色

但是染色不能出现奇环 并且每三个人吃的不一样 我们可以考虑2*i 与 2*i+1 连接

符合题意

但是我们咋证明其不是奇环 

其实我们可以在纸上模拟一下即可 肯定是不合法的 

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int h[N],e[N<<1],ne[N<<1],idx,n,c[N];
vector<pair<int,int>>v;
bool flag;
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void bfs(int x){
    queue<int>q;
    q.push(x);
    c[x]=1;
    while(q.size()){
        auto t=q.front();q.pop();
        for(int i=h[t];~i;i=ne[i]){
            int j=e[i];
            if(!c[j]){
                c[j]=3-c[t];
                q.push(j);
            }else if(c[j]==c[t]){
                cout<<"NO"<<endl;
                flag=1;
            }
        }
    }
}
signed main(){
    fast
    cin>>n;
    v.clear();
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++){
        int a,b;cin>>a>>b;
        v.emplace_back(a,b);
        add(a,b),add(b,a);
    }
    for(int i=1;i<=n;i++){
        add(2*i,2*i-1),add(2*i-1,2*i);
    }
    for(int i=1;i<=n*2;i++){
        if(!c[i])bfs(i);
    }
    if(flag)return 0;
    for(auto i:v){
        cout<<c[i.first]<<' '<<c[i.second]<<endl;
    }
    return ~~(0^_^0);
}

CF1656E Equal Tree Sums

我超 卡常🐕

我也不知道咋证 感觉挺一眼的

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int n,h[N],e[N<<1],ne[N<<1],idx,c[N];
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
signed main(){
    fast
    int tt;cin>>tt;
    while(tt--){
        memset(h,-1,sizeof h);
        memset(c,0,sizeof c);
        idx=0;
        cin>>n;
        int v[N]={0};
        for(int i=1;i<n;i++){
            int a,b;cin>>a>>b;
            add(a,b),add(b,a);
            v[a]++;
            v[b]++;
        }
        queue<int>q;
        q.push(1);
        c[1]=1;
        while(q.size()){
            auto t=q.front();q.pop();
            for(int i=h[t];~i;i=ne[i]){
                int j=e[i];
                if(!c[j]){
                    c[j]=3-c[t];
                    q.push(j);
                }
            }
        }
        for(int i=1;i<=n;i++){
            if(c[i]==1)cout<<v[i]<<' ';
            else cout<<-v[i]<<' ';
        }
        cout<<endl;
    }
    return ~~(0^_^0);
}

CF1656E Equal Tree Sums

我们可以观察出来出来一个点到另一个点经过的简单路径都是奇数

而我们最高位都是偶数个

那我们就可以知道我们不管咋整都有最高位的就是1<<n

我们观察样例答案就是1<<n 我们不妨设这个就是答案

再想一下 既然要是我们答案是1<<n 我们就让其做根

然后构造出n-1 组让最大值<=1<<n 就可以了 事实上就可行的

我们考虑 k1+n k1 k2 k2+n 这种顺序

注意这个要用dfs这个是按深度来变化的 bfs的话就要多维护一个深度

int h[N],e[N<<1],ne[N<<1],idx,cnt=1,n,num[N],cnt1;
void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
void dfs(int u,int flag,int d[]){
    num[u]=cnt1++;
    for(int i=h[u];~i;i=ne[i]){
        int j=e[i];
        if(!d[j]){
            if(flag)d[j]=(1<<n)+cnt++;
            else d[j]=cnt++;
            dfs(j,flag^1,d);
        }
    }
}
signed main(){
    fast
    int tt;cin>>tt;
    while(tt--){
        idx=0;
        cin>>n;
        memset(h,-1,sizeof h);
        int d[N]={0};
        vector<pair<int,int>>v;
        for(int i=2;i<=(1<<n);i++){
            int a,b;cin>>a>>b;
            v.push_back({a,b});
            add(a,b),add(b,a);
        }
        cnt=1;
        d[1]=1<<n;dfs(1,0,d);
        cout<<1<<endl;
        for(int i=1;i<=(1<<n);i++){
            cout<<d[i]<<' ';
        }
        cout<<endl;
        for(auto i:v){
            if(num[i.second]<num[i.first])swap(i.first,i.second);
            if(d[i.second]>(1<<n))cout<<d[i.second]-(1<<n)<<' ';
            else cout<<d[i.second]+(1<<n)<<" ";
        }
        cout<<endl;
    }
    return ~~(0^_^0);
}

CF1682D Circular Spanning Tree

我们考虑无解的情况

可以看出要是奇数个1肯定是不合法的

因为是一颗树 所以我们构建不出来全0的情况 

然后我们考虑旋转s[]

让他变成0开头1结尾的

0...1 0....1 0.....1 然后我们就可以看成一条条链了

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define LL long long
#define endl '\n'
#define Endl '\n'
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);
int n;
char s[N];
signed main(){
    fast
    int tt;cin>>tt;
    while(tt--){
        cin>>n>>s+1;//buneng quan 0 && buneng dan 1
        int cnt=0,cnt0=0,cnt1=0;
        for(int i=1;i<=n;i++){
            if(s[i]=='0'){
                cnt=i;
                cnt0++;
            }else cnt1++;
        }
        if(cnt0==n||cnt1%2){
            cout<<"NO"<<endl;
            continue;
        }else cout<<"YES"<<endl;
        if(!cnt0){
            for(int i=2;i<=n;i++){
                cout<<1<<' '<<i<<endl;
            }
            continue;
        }
        for(int i=cnt;i>=1;i--){
            if(s[i-1]=='0')cnt--;
            else break;
        }
        int root=cnt,x=root,y;
        for(int i=cnt+1,j=1;j<n;i++,j++){
            if(i==n+1)i=1;
            y=i;
            cout<<x<<' '<<y<<endl;
            x=y;
            if(s[i]=='1')x=root;
        }
    }
    return ~~(0^_^0);
}

CF1328D Carousel

先特判全一样

然后分奇偶吧:

偶数就1212就可以了

奇数并且相邻数有一样类型的 那我们就可以让这个相邻的染一种颜色 然后就把剩下的变成偶数了

奇数并且相邻都不一样 那我们怎么整都是3了

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5+10;
const int M = 1<<16;
const int mod = 1e9+7;
#define int long long
#define LL long long
#define endl '\n'
#define Endl '\n'
#define yes cout<<"YES"<<endl;
#define no cout<<"NO"<<endl;
#define _ 0
#define inf 0x3f3f3f3f3f3f3f3f
#define fast ios::sync_with_stdio(false);cin.tie(nullptr);

signed main(){
    fast
    int T;cin>>T;
    while(T--){
        int n;cin>>n;
        bool flag=0,flag1=1;
        vector<int>a(n+1);
        for(int i=1;i<=n;++i)cin>>a[i];
        for(int i=1;i<=n;++i){
            int p=i-1;
            if(p==0)p=n;
            if(a[i]==a[p])flag=1;
            else flag1=0;
        }
        if(flag1){
            cout<<1<<endl;
            for(int i=1;i<=n;++i)cout<<"1 ";
            cout<<endl;
        }else if(n%2==0){
            cout<<2<<endl;
            for(int i=1;i<=n/2;++i)cout<<"2 1 ";
            cout<<endl;
        }else if(flag){
            cout<<2<<endl;
            flag=0;
            for(int i=1;i<=n;++i){
                int p=i-1;
                if(p==0)p=n;
                if(flag)cout<<2-(i%2);
                else if(a[i]==a[p])cout<<2-(i%2),flag=1;
                else cout<<i%2+1;
            }
            cout<<endl;
        }else{
            cout<<3<<endl;
            for(int i=1;i<n;++i){
                cout<<i%2+1<<endl;
            }
            cout<<3<<endl;
        }
    }
    return ~~(0^_^0);
}

CF1338B Edge Weight Assignment

min:很好观察出来吧 要是任意两叶子的距离有奇数那么就3 没有就是1

这个可以只用对一个叶子dfs一遍就是了 我也不会证 但是感性理解了一下感觉很对

max:他们说是边数减去同深度的叶子节点就是了 不懂 但是是对的

每个都是遍历一遍点 所以时间复杂度是O(n)的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值