zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 58 (Rated for Div. 2)

    A. Minimum Integer

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=1e3+10;
    struct node{
        ll num,mag;
        friend bool operator <(const node &a,const node &b){
            return a.mag>b.mag;
        }
    }a[maxn];
    int n;
    ll p[70];
    ll add(ll x,ll val){
        for(int i=60;i>=0;i--)
        {
            if(x&(1<<i))
            {
                if(!p[i]){
                    p[i]=x;
                    break;
                }else{
                    x=x^p[i];
                }
            }
        }
        if(x>0)return val;
        return 0;
    }
    int main(){
        while(cin>>n)
        {
            ll l,r,d;
            while(n--)
            {
                cin>>l>>r>>d;
                if(d<l)printf("%lld
    ",d);
                else{
                    printf("%lld
    ",(r/d+1)*d);
                    
                }
            }
        }
    }
    View Code

    B. Accordion

    小模拟,从前往后扫到第一个 [: ,从后往前扫到第一个 :] ,然后数中间的 “|” 就可以了。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=5e5+10;
    char s[maxn];
    int main(){
        while(scanf("%s",s+1)!=EOF)
        {
            int flag=0,p1=-1,p2=-1,len=strlen(s+1);
            for(int i=1;i<=len;i++)
            {
                if(flag==0)
                {
                    if(s[i]=='[')flag=1;
                }else{
                    if(s[i]==':'){
                        p1=i;
                        break;
                    }
                }
            }
            flag=0;
            for(int i=len;i>p1&&i>0;i--)
            {
                if(flag==0)
                {
                    if(s[i]==']')flag=1;
                }else{
                    if(s[i]==':'){
                        p2=i;
                        break;
                    }
                }
            }
            if(p1==-1||p2==-1){
                printf("-1
    ");
                continue;
            }
            int tot=0;
            for(int i=p1+1;i<p2;i++)
            {
                if(s[i]=='|')tot++;
            }
            printf("%d
    ",tot+4);
        }
    }
    View Code

    C. Division and Union

    题意:把给出的区间分成两部分,使不同部分的区间,不会有交点。

    按 l 排序一遍,如果 l 小于前面最大的 r ,则必须和前面分在同一个群,否则就到第二个群。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=2e5+10;
    int T,n;
    struct node{
        int l,r;
        int id;
        friend bool operator <(const node &a,const node &b)
        {
            return a.l<b.l;
        }
    }a[maxn]; 
    int ans[maxn];
    int main(){
        cin>>T;
        while(T--)
        {
            cin>>n;
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&a[i].l,&a[i].r);
                a[i].id=i;
            }
            sort(a+1,a+1+n);
            int maxx=a[1].r,tep=0,flag=0;
            ans[a[1].id]=1;
            for(int i=2;i<=n;i++)
            {
                if(a[i].l<=maxx){
                    ans[a[i].id]=1+tep;
                }else{
                    ans[a[i].id]=1+1-tep;
                    tep=1-tep;
                    flag=1;
                }
                maxx=max(maxx,a[i].r);
                
            }
            if(flag==0)puts("-1");
            else{
                for(int i=1;i<=n;i++)
                {
                    printf("%d%c",ans[i]," 
    "[i==n]);
                }
            }
        }
    }
    View Code

    D. GCD Counting

    题意:给出一颗点带权的数,求任意两点简单路径上的点gcd大于1的长度最大是多少。

    题解:

         gcd大于1即不互质,若一条路径是合法路径,则必定有一个大于1的公共质因子。所以我们可以对每个小于2e5的质数重新建树,然后再求树的直径。

           建图是怎么建的呢,其实只要把边读入的时候,就把边塞到各自的质因子背包里面去,最后把每个背包的边都建立出来,跑树上直径。

      但是有一个问题是,小于2e5的质数有一万多个,树的直径又是O(n)的,这样看上去会超时,我也困扰了好久。其实,两个点之间的公共gcd的质因子个数最多就十个左右,(再多就爆了)也就意味着每个点最多被建图十次,所以如果跑树的直径最后的总计算次数也就是10*O(n)左右,不会超时,这类问题以后要注意,明明很快就想到标算的,但迟迟不敢动手。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=2e5+10;
    int prim[maxn],n,u,v,a[maxn];
    int gcd(int a,int b){
        return b==0?a:gcd(b,a%b);
    }
    void initPrim(){
        for(int i=2;i<=2e5/2;i++)
        {
            for(int j=2;i*j<=2e5;j++)
            {
                prim[i*j]=1;
            }
        }
    }
    struct edge{
        int u,v;
    };
    vector<edge>ve[maxn];
    vector<int >e[maxn];
    vector<int >jont;
    bool vis[maxn];
    int ans=0;
    int dfs(int u,int fa,int dep){
        vis[u]=1;
        int f=0;
        int flink=0,slink=0;
        for(int i=0;i<e[u].size();i++)
        {
            int v=e[u][i];
            if(v==fa)continue;
            f=1;
            int tep=dfs(v,u,dep+1);
            if(tep>flink)slink=flink,flink=tep;
            else if(tep>slink)slink=tep;
        }
        ans=max(ans,max(dep+flink,flink+1+slink));
        return flink+1;
        
    }
    int main(){
        initPrim();
        while(cin>>n)
        {
            ans=1;
            int fff=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
                if(a[i]>1)fff=1;
            }
            for(int i=2;i<=2e5;i++)ve[i].clear();
            for(int i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                int k=gcd(a[u],a[v]);
                if(k>1){
                    for(int j=1;j*j<=k;j++)
                    {
                        if(k%j==0)
                        {
                            if(j!=1&&prim[j]==0)    ve[j].push_back({u,v});
                            if(j*j!=k&&prim[k/j]==0) ve[k/j].push_back({u,v});
                        }
                    }
                }
            }
            if(fff==0){
                puts("0");
                continue;
            }
            clr(vis,1);
            for(int i=2;i<=2e5;i++)
            {
                if(!prim[i])
                {
                    for(int j=0;j<ve[i].size();j++)
                    {
                        if(vis[ve[i][j].u]==1)
                        {
                            jont.push_back(ve[i][j].u);
                        }
                        if(vis[ve[i][j].v]==1)
                        {
                            jont.push_back(ve[i][j].v);
                        }
                        vis[ve[i][j].u]=0;
                        vis[ve[i][j].v]=0;
                        e[ve[i][j].u].push_back(ve[i][j].v);
                        e[ve[i][j].v].push_back(ve[i][j].u);
                    }
                    for(int j=0;j<jont.size();j++)
                    {
                        vis[jont[j]]=0;
                    }
                    for(int j=0;j<jont.size();j++)
                    {
                        int u=jont[j];
                        if(!vis[u]){
                            dfs(u,0,1);
                        }
                    }
                    for(int j=0;j<jont.size();j++)
                    {
                        e[jont[j]].clear();
                    }
                    jont.clear();
                }
            }
            cout<<ans<<endl;
        }
    }
    View Code

    E. Polycarp's New Job

    为什么这会是E题,一开始我以为是求有几张钞票能被塞进去,看了样例才发现我想太多了。

    反正就钞票放进去的时候,固定格式,短的一边在下面,钱包也是这样,分别记录长边和短边的最大值,比一下即可。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=2e5+10;
    int T,n;
    struct node{
        int l,r;
        int id;
        friend bool operator <(const node &a,const node &b)
        {
            return a.l<b.l;
        }
    }a[maxn]; 
    int ans[maxn];
    int main(){
        cin>>T;
        int maxl=0,maxr=0,l,r;
        char op[3];
        while(T--)
        {
            scanf("%s%d%d",op,&l,&r);
            if(op[0]=='+'){
                if(l>r)swap(l,r);
                maxl=max(maxl,l),maxr=max(maxr,r);
            }else{
                if(l>r)swap(l,r);
                if(l>=maxl&&r>=maxr)printf("YES
    ");
                else puts("NO");
            }
        }
    }
    View Code

    F. Trucks and Cities

    好题,题解移步我的另外一篇博客  点这里

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=402;
    ll ans;
    int dp[maxn][maxn][maxn],a[maxn];
    int n,m;
    int main(){
        while(cin>>n>>m)
        {
            ans=0;
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&a[i]);
            }
            for(int i=1;i<=n;i++)
            {
                for(int j=i;j<=n;j++)
                {
                    dp[i][j][0]=a[j]-a[i];
                }
            }
            for(int k=1;k<=n;k++)
            {
                for(int i=1;i<=n;i++)
                {
                    int w=i;
                    for(int j=i;j<=n;j++)
                    {
                        while(w<j&&max(dp[i][w][k-1],a[j]-a[w])>max(dp[i][w+1][k-1],a[j]-a[w+1]))w++;
                        dp[i][j][k]=max(dp[i][w][k-1],a[j]-a[w]);
                    }
                }
            }
            int s,f,r;
            ll c;
            while(m--)
            {
                scanf("%d%d%lld%d",&s,&f,&c,&r);
                ans=max(ans,dp[s][f][r]*c);
            }
            cout<<ans<<endl;
        }
    } 
    View Code

    G. (Zero XOR Subset)-less

    题意:给出一个序列,试将其划分为尽可能多的非空子段,满足每一个元素出现且仅出现在其中一个子段中,且在这些子段中任取若干子段,它们包含的所有数的异或和不能为0.

    思路:先处理出前缀异或,这样选择更多的区间其实就相当于选择更多的前缀异或,并且这些前缀异或不能异或出0,这就变成了线性基的基础题了。贪心的放,能放就放。不能放就意味着线性基的add函数里面的val最后变成了0,也就是当前已经插入的线性基已经可以异或出正在插入的数了,所以不能放。

    #include<bits/stdc++.h>
    #define clr(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long ll; 
    const int maxn=2e5+10;
    ll a[maxn],p[40],s[maxn];
    int n;
    int add(ll val){
        for(int i=30;i>=0;i--)
        {
            if(val&(1<<i)){
                if(!p[i]){
                    p[i]=val;
                    return 1;
                }
                val^=p[i];
            }
        }
        return 0;
    }
    int main(){
        while(cin>>n)
        {
            clr(p,0);
            for(int i=1;i<=n;i++)
            {
                scanf("%lld",&a[i]);
                s[i]=s[i-1]^a[i];
            }
            if(s[n]==0){
                puts("-1");
                continue;
            }
            int ans=0;
            for(int i=n;i>0;i--)
            {
                ans+=add(a[i]);
            }
            cout<<ans<<endl;
        }
    } 
    View Code
  • 相关阅读:
    在ConcurrentModificationException异常上的联想
    记录一下自己爬虎牙LOL主播的爬虫思路
    ajax解决跨域问题
    解决多线程下数据库操作问题
    浅谈时间复杂度
    想一下,最大公约数怎么求
    IO流与IO缓冲
    循环移位
    3Sum探讨(Java)
    Two Sum(两个数的相加)
  • 原文地址:https://www.cnblogs.com/mountaink/p/10348934.html
Copyright © 2011-2022 走看看