练习记录-cf-Codeforces Round 909 (Div. 3)(A-G)
好久没打div了 然后思维太差 现在被抓回来继续打了QWQ
终于被我逮到一场G数据结构的 ak了 既然ak了就开心地写下题解 别被hack别被hack别被hack
这场挺简单的 之前打的div3都好难qaq
A. Game with Integers
题意:给一个数字,两人轮流操作,可以+1或者-1 先手能把这个数变成3的倍数就获胜,否则失败
解法:先手第一步不能变成3的倍数那么永远都不行,所以就判这个数+1/-1是不是3的倍数

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; void solve(){ int n;cin>>n; if((n-1)%3==0||(n+1)%3==0){ cout<<"First\n"; } else{ cout<<"Second\n"; } } signed main(){ int t; cin>>t; while(t--) solve(); }
B. 250 Thousand Tons of TNT
题意:你需要选一个k k能整除n,然后从前往后每k个装一车,问两车最大的差值的最大值
解法:枚举n的所有因子,用前缀和快速处理出1-k k+1-2*k ...的重量,然后记录最大最小值,一直取max就好了
复杂度证明:可能写的不太准,一个1e5的数的因子应该不超过17个 (全是2的情况最多), 那么不同因子的排列组合方法一共有2^17种,所以枚举的复杂度不超过1e5,中间还有重复,我算不太来,反正挺符合的()。然后用前缀和加速就是里面O1 总体1e5

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f3f3f3f3f; #define int ll int a[MAXN]; int pre[MAXN]; void solve(){ int n;cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; pre[i]=pre[i-1]+a[i]; } int ans=0; for(int i=1;i<n;i++){ if(n%i) continue; int mx=0,mn=inf; for(int j=1;j<=n;j+=i){ int st=j,ed=j+i-1; mx=max(mx,pre[ed]-pre[st-1]); mn=min(mn,pre[ed]-pre[st-1]); } if(mn!=inf) ans=max(ans,mx-mn); } cout<<ans<<"\n"; } signed main(){ close; int t;cin>>t; while(t--) solve(); }
C. Yarik and Array
这题不多说 最大区间和dp改下就行了

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; #define int ll int dp[MAXN],a[MAXN]; void solve(){ int n;cin>>n; for(int i=1;i<=n;i++) dp[i]=0; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++){ if(i==1||(abs(a[i]%2)!=abs(a[i-1]%2))){ dp[i]=max(a[i],dp[i-1]+a[i]); } else dp[i]=a[i]; } int ans=inf*-1; for(int i=1;i<=n;i++){ ans=max(ans,dp[i]); } cout<<ans<<"\n"; } signed main(){ close; int t;cin>>t; while(t--) solve(); }
D. Yarik and Musical Notes
题意:问对于任意两个aiaj,满足匹配的2^ai,2^aj有多少对,匹配方法就是互相pow相等
解法:打了个表发现对于两个不同的数 只有(1,2)是符合情况的,相同的肯定符合,map记录出现次数 然后组合一下就行了

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; #define int ll map<int,int> mp; void solve(){ int n;cin>>n; mp.clear(); for(int i=1;i<=n;i++){ int a;cin>>a; mp[a]++; } int t1=mp[1]; int t2=mp[2]; int ans=0; ans+=t1*t2; for(auto &it:mp){ int cnt=it.second; if(cnt>=2){ ans+=(cnt*(cnt-1))/2; } } cout<<ans<<"\n"; } signed main(){ close; int t;cin>>t; while(t--) solve(); }
E. Queue Sort
题意:题目给出排序方法:先把第一个元素塞到最后,然后一直往前挪直到前面的数小于等于这个数。问能否通过有限次排序让数组递增,并输出最少次数
解法:分析一下-1的情况,我们发现如果此时头是最小值(相同取最左边),那么不管怎么挪后面都动不了了,所以我们判一下最小值在哪,后面是否升序就行了

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; #define int ll int a[MAXN]; void solve(){ int n;cin>>n; for(int i=1;i<=n;i++){ cin>>a[i]; } int mx=1; for(int i=1;i<=n;i++){ if(a[i]<a[mx]){ mx=i; } } int flag=1; for(int i=mx+1;i<=n;i++){ if(a[i]<a[i-1]) flag=0; } if(!flag){ cout<<"-1\n"; return; } cout<<mx-1<<"\n"; } signed main(){ close; int t;cin>>t; while(t--) solve(); }
F. Alex's whims
题意:构造一棵树,每给出一次询问x,表示需要移动至多一个节点让树上存在两个距离为x的叶子节点,输出移动方案
解法:我发现,对于一个链(1-2-3-..-n),叶子节点距离为n-1,如果我们把最后一个节点放到2节点上 那长度就变成2,3上就变成3....这是一个很有意思的规律,所以它要求长度是哪个我们就把节点n移动到哪个节点上就行了

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; void solve(){ int n,q;cin>>n>>q; for(int i=1;i<n;i++){ cout<<i<<" "<<i+1<<"\n"; } int now=n-1; while(q--){ int k;cin>>k; if(k==now){ cout<<"-1 -1 -1\n"; continue; } else{ cout<<n<<" "<<now<<" "<<k<<"\n"; now=k; } } } signed main(){ close; int t;cin>>t; while(t--) solve(); }
G. Unusual Entertainment
题意:q次询问,问一个打乱的排列l-r中,是否有点在x的子树内
解法:很容易想到,我们可以通过dfs维护dfs序,然后dfn在一个连续区间内的点都在x的子树内,此处我拉的树剖板子。
问题现在转化成了 对于一个区间l-r 是否有数字的dfn在一个连续区间ab内。
对这个问题我们考虑离线然后扫描线 对于一个单独的问题,我们需要知道在l-1以前 dfn在(a,b)内的数有x个,以及在r以前 ( a,b)区间的数有y个,这样的话 如果y比x大,就说明在l-r里面增加了新的属于(a,b)的数 那么对于这个询问答案就是yes 否则no
在树状数组上统计(a,b)的答案
就for一遍排列数组,然后对在每个点上的询问,分别记录两个ans 最后看是否变大就是答案了
记得清空算dfn的东西和询问和把加的树状数组减回去

#include<bits/stdc++.h> #define close std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; typedef long long ll; const ll MAXN = 3e5+7; const ll mod = 1e9+7; const ll inf = 0x3f3f3f3f; vector<int> adj[MAXN]; vector<array<int,4> > Q[MAXN]; int a[MAXN]; int siz[MAXN],f[MAXN],hson[MAXN],deep[MAXN],top[MAXN],dfn[MAXN],rdfn[MAXN],rak[MAXN],cnt; int t[MAXN]; int ans[2][MAXN]; int lowbit(int x) { return x&-x; } ll getsum(int x) { ll sum=0; while(x) { sum+=t[x]; x-=lowbit(x); } return sum; } void addv(int x,int val) { while(x<=MAXN) { t[x]+=val; x+=lowbit(x); } } void tree_build(int u,int fa) {//重链优先搜索 siz[u]=1; f[u]=fa; hson[u]=0; for(auto &v:adj[u]) { if(v==fa) continue; deep[v]=deep[u]+1; tree_build(v,u); siz[u]+=siz[v]; if(hson[u]==0||siz[v]>siz[hson[u]]) hson[u]=v; } } void tree_decom(int u,int t) {//dfn序 top[u]=t; cnt++; dfn[u]=cnt; rak[cnt]=u; if(hson[u]!=0) { tree_decom(hson[u],t); for(auto &v:adj[u]) { if(hson[u]!=v&&v!=f[u]) tree_decom(v,v); } } rdfn[u]=cnt; } void solve() { cnt=0; int n,q; cin>>n>>q; for(int i=1;i<=q;i++) ans[0][i]=0,ans[1][i]=0; for(int i=1; i<=n; i++) { adj[i].clear(); Q[i].clear(); } for(int i=1; i<n; i++) { int u,v; cin>>u>>v; adj[u].push_back(v); adj[v].push_back(u); } tree_build(1,0); tree_decom(1,1); for(int i=1; i<=n; i++) cin>>a[i]; for(int i=1; i<=q; i++) { int l,r,x; cin>>l>>r>>x; int a=dfn[x]; int b=rdfn[x]; Q[l].push_back({0,a,b,i}); Q[r].push_back({1,a,b,i}); } for(int i=1;i<=n;i++){ for(auto &it:Q[i]){ int ty=it[0]; int a=it[1]; int b=it[2]; int id=it[3]; if(ty==0) ans[ty][id]=getsum(b)-getsum(a-1); } int k=dfn[a[i]]; addv(k,1); for(auto &it:Q[i]){ int ty=it[0]; int a=it[1]; int b=it[2]; int id=it[3]; if(ty==1) ans[ty][id]=getsum(b)-getsum(a-1); } } for(int i=1;i<=q;i++){ if(ans[0][i]<ans[1][i]) cout<<"YES\n"; else cout<<"NO\n"; } for(int i=1;i<=n;i++) addv(i,-1); cout<<"\n"; } signed main() { close; int t; cin>>t; while(t--) solve(); }