• 牛客小白月赛62


    比赛链接:牛客小白月赛62_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ (nowcoder.com)

    A: 幼稚园的树

    方法:模拟

    代码:

    1. #include
    2. #define all(v) v.begin(),v.end()
    3. #define int long long
    4. #define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    5. #define pi acos(-1)
    6. using namespace std;
    7. const int INF=0x3f3f3f3f;
    8. const int N=2e6+10;
    9. typedef pair<int,int>PII;
    10. int h[N];
    11. inline void solve(){
    12. int a,k,b,n,m;cin>>n;
    13. for(int i=1;i<=n;i++) cin>>h[i];
    14. cin>>a>>k>>b>>m;
    15. m--;
    16. while(m--){
    17. for(int i=1;i<=n;i++) h[i]+=a;
    18. for(int i=1;i<=n;i++){
    19. if(h[i]>k) h[i]=b;
    20. }
    21. }
    22. for(int i=1;i<=n;i++) cout<" ";
    23. cout<<"\n";
    24. }
    25. signed main(){
    26. fast;
    27. int T;cin>>T;
    28. while(T--) solve();
    29. }

    B:剩下的数

    方法:数论——>结论

    分析:先通过手撸几组样例过后,我们会发现,答案只有0或1。

    证明:

    ps:定义整个环的和为sum      询问值为x

    如果sum%x==0,那么我们就可以删掉整个环。则ans=0

    如果sum%x!=0,ans=1。为什么?

    我们发现,L~R中的每个数 mod x,会出现余数,而这些余数值的区间刚好为[0,X-1]。那么L~R中,一定会存在一个数是跟sum同余的。所以,我们任意选出一个数,删掉剩余的数即可。此时ans=1.(可能有点懵?看组样例吧)

    ps:现在应该懂了吧?(Q.Q)

    代码:

    1. #include
    2. #define all(v) v.begin(),v.end()
    3. #define int long long
    4. #define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    5. #define pi acos(-1)
    6. using namespace std;
    7. const int INF=0x3f3f3f3f;
    8. const int N=2e6+10;
    9. typedef pair<int,int>PII;
    10. inline void solve(){
    11. int l,r,m;cin>>l>>r>>m;
    12. int sum=(l+r)*(r-l+1)/2;//等差数列求和公式
    13. while(m--){
    14. int x;cin>>x;
    15. if(sum%x==0) cout<<"0\n";
    16. else cout<<"1\n";
    17. }
    18. }
    19. signed main(){
    20. fast;
    21. int T;cin>>T;
    22. while(T--) solve();
    23. }

    C:数列的划分

    思路:质因数分解

    分析:用set存a数组里面每个数的质因数。再判断b数组的每个质因数是否在set里面出现过。为什么呢?因为如果要互相独立,那么P(b数组中每个数的质因数)\notinset。如果一旦属于了,就一定存在两个对应的数的gcd!=1。

    代码:

    1. #include
    2. #define all(v) v.begin(),v.end()
    3. //#define int long long
    4. #define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    5. #define pi acos(-1)
    6. using namespace std;
    7. const int INF=0x3f3f3f3f;
    8. const int N=2e6+10;
    9. typedef pair<int,int>PII;
    10. int a[N],b[N];
    11. inline void solve(){
    12. int n;cin>>n;
    13. for(int i=1;i<=n;i++) cin>>a[i];
    14. for(int i=1;i<=n;i++) cin>>b[i];
    15. set<int> aa;
    16. for(int i=1;i<=n;i++){
    17. int x=a[i];
    18. for(int j =2;j<=x/j;j++){//筛质因数
    19. while(x%j==0){
    20. aa.insert(j);
    21. x/=j;
    22. }
    23. }
    24. if(x>1) aa.insert(x);//最后筛完,剩余的质因数(如果为1,没有必要放入set)
    25. }
    26. for(int i=1;i<=n;i++){
    27. int x=b[i];
    28. for(int j=2;j<=x/j;j++){
    29. while(x%j==0){
    30. if(aa.count(j)){
    31. cout<<"No\n";return;
    32. }
    33. x/=j;
    34. }
    35. }
    36. if(x>1&&aa.count(x)){
    37. cout<<"No\n";return;
    38. }
    39. }
    40. cout<<"Yes\n";
    41. }
    42. int main(){
    43. fast; solve();
    44. }

    D:子树的大小

    思路:思维

    分析:一开始我以为用DFS搜索。然而遇到不会建树的问题,且还会TLE。看大佬的题解,才发现这题很简单。

    我们拿三叉树进行举例: 

    我们定义:L为所要查询跟节点的子树最右边的位置  R跟L同理

    所以,在给定一个需要查询的节点时,就可以算出子树每一层的节点数。最后累加即可。 

    代码: 

    1. #include
    2. #define all(v) v.begin(),v.end()
    3. #define int long long
    4. #define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    5. #define pi acos(-1)
    6. using namespace std;
    7. const int INF=0x3f3f3f3f;
    8. const int N=2e6+10;
    9. typedef pair<int,int>PII;
    10. inline void solve(){
    11. int n,m,k;cin>>n>>k>>m;
    12. n--;
    13. while(m--){
    14. int q;cin>>q;
    15. if(k==1){//可以当作链表结构
    16. cout<1<<"\n";continue;
    17. }
    18. int ans=0;
    19. int l=q,r=q;
    20. while(l<=n){
    21. ans+=min(n,r)-l+1;
    22. l=l*k+1;//下一层的最左边
    23. r=r*k+k;//下一层的最右边
    24. }
    25. cout<"\n";
    26. }
    27. }
    28. signed main(){
    29. fast;
    30. int T;cin>>T;
    31. while(T--) solve();
    32. }

    E:剖分

    思路:树上差分

    题解:具体看代码注释

    代码:

    1. #include
    2. #define all(v) v.begin(),v.end()
    3. #define int long long
    4. #define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    5. #define pi acos(-1)
    6. using namespace std;
    7. const int INF=0x3f3f3f3f;
    8. const int N=2e7+10;
    9. typedef pair<int,int>PII;
    10. int add[N],sum[N],st[N];/*add:以i为根节点的子树 sum:i号节点的权重 st:存答案*/
    11. ps:add[i]:也表示了i号节点的权重
    12. inline void solve(){
    13. int n,m;
    14. cin>>n>>m;
    15. for(int i=1;i<=m;i++){
    16. int op;cin>>op;
    17. int x;cin>>x;
    18. if(op==1) add[x]++;//以x为根节点的子树都+1
    19. else if(op==2) add[x]--,add[1]++;//可以看作,以x为根节点的子树都先-1,再使整个树+1
    20. else if(op==3){//路径上各个节点的权重+1
    21. while(x) sum[x]++,x/=2;
    22. }
    23. else{//跟op==2的操作同理
    24. add[1]++;
    25. while(x) sum[x]--,x/=2;
    26. }
    27. }
    28. for(int i=1;i<=n;i++){
    29. int l=2*i;//左子树(儿子)
    30. int r=2*i+1;//右子树(儿子)
    31. sum[i]+=add[i];//i号节点的权重=以i为根的权重
    32. add[l]+=add[i];//这里给图说明一下
    33. add[r]+=add[i];
    34. }
    35. for(int i=1;i<=n;i++) st[sum[i]]++;//记录答案
    36. for(int i=0;i<=m;i++) cout<" ";//输出答案
    37. }
    38. signed main(){
    39. fast;solve();
    40. }

    仔细思考一下。如果B节点被加了X次,那么他的子树(节点)D也被加了X次 。所以D的权重=D本身的权重加上他父亲的权重=add[D]+add[B]。B是D的父亲,根据二叉树的基本知识,节点i的左儿子是2*i,右儿子 2*i+1。那么给定儿子的节点k。他的父亲节点就是k/2。

    PS:再次深刻理解add和sum数组的含义!!!

  • 相关阅读:
    中石油勘探院张弢:从业务到架构全面探讨中国石油的数字化转型之路
    解密游戏推荐系统的建设之路
    聊聊Spring的Aware接口
    [go]gg库绘图与添加文字
    竞赛 题目:基于LSTM的预测算法 - 股票预测 天气预测 房价预测
    Java校招120道面试题目合集
    arthas retransform热更新
    第五十六章 学习常用技能 - 执行 SQL 查询
    CentOS 7 手动安装OpenStack
    肾囊肿会出现什么异常?
  • 原文地址:https://blog.csdn.net/YuDuna/article/details/128188477