• Codeforces Round #613 选讲


    http://codeforces.com/contest/1285/problem/D

    从高位往低位看,如果某一位上全是一样的数字,则直接看下一位;如果某位上有0有1,表明这一位答案上一定有个1,但具体那个X是要取0还是取1,取决于后面的位数,由此可将数字按这一位的01分成两组,递归地解决问题。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int n;
     5 #define maxn 200011
     6 int a[maxn];
     7 
     8 int dfs(int x,int L,int R)
     9 {
    10     if (x<0) return 0;
    11     if (((a[R]>>x)&1)==0 || ((a[L]>>x)&1)==1) return dfs(x-1,L,R);
    12     int mid=L; for (;mid<=R && ((a[mid]>>x)&1)==0;mid++);
    13     return (1<<x)+min(dfs(x-1,L,mid-1),dfs(x-1,mid,R));
    14 }
    15 
    16 int main()
    17 {
    18     scanf("%d",&n);
    19     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    20     sort(a+1,a+1+n);
    21     printf("%d
    ",dfs(29,1,n));
    22     return 0;
    23 }
    View Code

    http://codeforces.com/contest/1285/problem/E

    思路点在于找到“删除后会增加/减少的那些线段并后的区间”,即什么情况下,删除某个区间后,并后的区间与初始的并相比会变多/变少。变多:对一个坐标x,如果此时x为某个线段的起点,且x刚好被且只被某线段i覆盖,则删去i后区间数+1。变少:如果某条线段的左端点本来就是初始并的某个左端点,那么删去之后会比初始并少去一个区间(当然可能还有新增加的,这由前一种情况统计)。采用扫描线的方法完成,把一个线段拆成两个修改操作,按坐标排序后分别统计初始答案和以上两种情况。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 int T,n,lq;
     5 #define maxn 400011
     6 struct SEG{int l,r;}a[maxn];
     7 struct QUES
     8 {
     9     int x,id,ty;
    10     bool operator < (const QUES &b) const {return x<b.x || (x==b.x && ty>b.ty);}
    11 }q[maxn<<1];
    12 void addq(int x,int id,int ty) {q[++lq]=(QUES){x,id,ty};}
    13 int diff[maxn];
    14 set<int> s;
    15 int main()
    16 {
    17     scanf("%d",&T);
    18     while (T--)
    19     {
    20         scanf("%d",&n);
    21         lq=0;
    22         for (int i=1;i<=n;i++) scanf("%d%d",&a[i].l,&a[i].r),addq(a[i].l,i,1),addq(a[i].r,i,-1);
    23         sort(q+1,q+1+lq);
    24         
    25         memset(diff,0,sizeof(diff));
    26         int cnt=0,init=0;
    27         for (int i=1,j,k;i<=lq;)
    28         {
    29             bool flag=(cnt==0);
    30             j=i;
    31             while (j<=lq && q[j].x==q[i].x) j++;
    32             k=i;
    33             for (;q[k].ty==1 && k<j;k++) cnt++;
    34             if (flag && cnt==1) diff[q[i].id]--;
    35             for (;q[k].ty==-1 && k<j;k++) cnt--;
    36             if (cnt==0) init++;
    37             i=j;
    38         }
    39         
    40         s.clear();
    41         for (int i=1,j,k;i<=lq;)
    42         {
    43             int add=(s.size()==1?(*s.begin()):-1);
    44             j=i;
    45             while (j<=lq && q[j].x==q[i].x) j++;
    46             k=i;
    47             for (;q[k].ty==1 && k<j;k++) s.insert(q[k].id);
    48             if (s.size()>1 && ~add) diff[add]++;
    49             for (;q[k].ty==-1 && k<j;k++) s.erase(s.lower_bound(q[k].id));
    50             i=j;
    51         }
    52         
    53         int ans=0;
    54         for (int i=1;i<=n;i++) ans=max(ans,init+diff[i]);
    55         printf("%d
    ",ans);
    56     }
    57     return 0;
    58 }
    View Code

    http://codeforces.com/contest/1285/problem/F

    枚举gcd,每次只考虑gcd的倍数(复杂度允许),将它们分别除以gcd后,在其中找乘积最大的互质的两个数。可以将它们从大到小排序入栈,每次一个数x入栈后,若监测到栈中存在与他互质的数就不停弹栈,弹到没有为止,最后弹出去的那个就是与x互质且最大的数。与x互质的数的数量即$sum_{d|x} mu(d) imes cnt_d$,其中$cnt_d$为$d$的倍数个数(可以考虑两数互质的情况然后推广可得此式)。每次可枚举x的约数计算(复杂度++)。总复杂度为每个数约数个数的平方之和。

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 
     5 int n;
     6 #define maxn 200011
     7 #define MAXNUM 100000
     8 int a[maxn];
     9 bool cmp(int a,int b) {return a>b;}
    10 
    11 vector<int> Div[maxn],mul[maxn];
    12 int miu[maxn],pri[maxn],lp=0; bool vis[maxn];
    13 void makeprime(int n)
    14 {
    15     miu[1]=1;
    16     for (int i=2;i<=n;i++)
    17     {
    18         if (!vis[i]) pri[++lp]=i,miu[i]=-1;
    19         for (int j=1;j<=lp && 1ll*i*pri[j]<=n;j++)
    20         {
    21             vis[i*pri[j]]=1;
    22             miu[i*pri[j]]=-miu[i];
    23             if (i%pri[j]==0) {miu[i*pri[j]]=0; break;}
    24         }
    25     }
    26 }
    27 
    28 int top=0,sta[maxn],cnt[maxn];
    29 
    30 int main()
    31 {
    32     scanf("%d",&n);
    33     for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    34     sort(a+1,a+1+n,cmp);
    35     
    36     for (int i=1;i<=MAXNUM;i++)
    37         for (int j=i;j<=MAXNUM;j+=i)
    38             Div[j].push_back(i);
    39     
    40     for (int i=1;i<=n;i++)
    41         for (int j=0;j<Div[a[i]].size();j++)
    42             mul[Div[a[i]][j]].push_back(a[i]/Div[a[i]][j]);
    43     
    44     makeprime(MAXNUM);
    45     
    46     LL ans=0;
    47     for (int i=1;i<=MAXNUM;i++) if (mul[i].size()>0)
    48     {
    49         top=0;
    50         for (int j=0,now,last;j<mul[i].size();j++)
    51         {
    52             last=0; now=mul[i][j];
    53             while (1)
    54             {
    55                 int tot=0;
    56                 for (int k=0;k<Div[now].size();k++) tot+=miu[Div[now][k]]*cnt[Div[now][k]];
    57                 if (tot>0)
    58                 {
    59                     last=sta[top];
    60                     for (int k=0;k<Div[last].size();k++) cnt[Div[last][k]]--;
    61                     top--;
    62                 }
    63                 else
    64                 {
    65                     ans=max(ans,1ll*last*now*i);
    66                     break;
    67                 }
    68             }
    69             sta[++top]=now;
    70             for (int k=0;k<Div[now].size();k++) cnt[Div[now][k]]++;
    71         }
    72         while (top)
    73         {
    74             int last=sta[top];
    75             for (int k=0;k<Div[last].size();k++) cnt[Div[last][k]]--;
    76             top--;
    77         }
    78     }
    79     
    80     printf("%lld
    ",ans);
    81     return 0;
    82 }
    View Code
  • 相关阅读:
    边工作边刷题:70天一遍leetcode: day 35
    边工作边刷题:70天一遍leetcode: day 36
    边工作边刷题:70天一遍leetcode: day 37-2
    边工作边刷题:70天一遍leetcode: day 37
    边工作边刷题:70天一遍leetcode: day 37-1
    边工作边刷题:70天一遍leetcode: day 38-2
    边工作边刷题:70天一遍leetcode: day 38-1
    边工作边刷题:70天一遍leetcode: day 38
    边工作边刷题:70天一遍leetcode: day 38-2
    边工作边刷题:70天一遍leetcode: day 38-1
  • 原文地址:https://www.cnblogs.com/Blue233333/p/12194273.html
Copyright © 2020-2023  润新知