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)的