Codeforces Round #608 (Div. 2) && Codeforces Round #607 (Div. 2)

Codeforces Round #607 (Div. 2)
A - Suffix Three

#include<bits/stdc++.h>
using namespace std;
int main()
{
    string s;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        cin>>s;
        if(s[s.size()-2]=='p'&&s[s.size()-1]=='o')
            cout<<"FILIPINO"<<endl;
        else if(s[s.size()-5]=='m'&&s[s.size()-4]=='n'&&s[s.size()-3]=='i'&&s[s.size()-2]=='d'&&s[s.size()-1]=='a')
            cout<<"KOREAN"<<endl;
        else cout<<"JAPANESE"<<endl;
    }
}

B - Azamon Web Services
O(n^3)的做法加上小剪枝(stl的cmp有多快我不知道)

#include<bits/stdc++.h>
using namespace std;
int T;
string s,t;
int main()
{
    cin>>T;
    while(T--)
    {
        cin>>s>>t;
        if(s<t) cout<<s<<endl;
        else
        {
            bool flag=false;
            for(int i=0;i<s.size()&&!flag;i++)
                for(int j=i+1;j<s.size()&&!flag;j++)
            {
                if(s[i]==s[j]||s[j]>t[i]) continue;
                swap(s[i],s[j]);
                if(s<t)
                {
                    flag=true;
                    cout<<s<<endl;
                    break;
                }
                swap(s[i],s[j]);
            }
            if(!flag) cout<<"---"<<endl;
        }
    }
}

C - Cut and Paste
题目转弯瞎说一大堆,其实就是把后面的一段复制来复制去,那么直接模拟即可

如果字符串的长度大于x了只有计数,否则在计数的同时把字符串加长。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
string s;
int main()
{
    int t;cin>>t;
    while(t--)
    {
        int x;
        cin>>x>>s;
        ll len=s.size(),bk=s.size();
        bool flag=false;
        for(int i=0;i<x;i++)
        {
            if(i>=s.size()) break;
            if(!flag)
            {
                if(bk>0) bk--;
                string k=s.substr(i+1,bk);
                if(s[i]-'0'==2) s+=k;
                if(s[i]-'0'==3) s+=k+k;
                len=(len+bk*(s[i]-'0'-1))%mod;
                bk=bk*(s[i]-'0')%mod;
                if(len>x) flag=true;
            }
            else
            {
                if(bk>0) bk--;
                len=(len+bk*(s[i]-'0'-1))%mod;
                bk=bk*(s[i]-'0')%mod;
            }
        }
        printf("%lld\n",len);
    }
}

D - Beingawesomeism
答案只有0~4和无解几种可能,分类讨论:
无解:矩阵全为P
0次:矩阵全为A
1次:矩阵在边界一行或者一列全为A
2次:矩阵在四个顶点有一个A或者有某行某列全为A
3次:矩阵在边界有一个A
4次:矩阵中有A即可

#include<bits/stdc++.h>
using namespace std;
const int N=77;
int n,m;
char s[N][N];
bool judge1()
{
    bool f1=true,f2=true,f3=true,f4=true;
    for(int i=1;i<=m;i++)
    {
        if(s[1][i]!='A') f1=false;
        if(s[n][i]!='A') f2=false;
    }
    for(int i=1;i<=n;i++)
    {
        if(s[i][1]!='A') f3=false;
        if(s[i][m]!='A') f4=false;
    }
    return f1|f2|f3|f4;
}
bool judge2()
{
    if(s[1][1]=='A'||s[1][m]=='A'||s[n][1]=='A'||s[n][m]=='A') return true;
    for(int i=1;i<=n;i++)
    {
        bool flag=true;
        for(int j=1;j<=m;j++)
        if(s[i][j]!='A') {flag=false;break;}
        if(flag) return true;
    }
    for(int j=1;j<=m;j++)
    {
        bool flag=true;
        for(int i=1;i<=n;i++)
            if(s[i][j]!='A'){flag=false;break;}
        if(flag) return true;
    }
    return false;
}
bool judge3()
{
    for(int i=1;i<=m;i++)
    {
        if(s[1][i]=='A') return true;
        if(s[n][i]=='A') return true;
    }
    for(int i=1;i<=n;i++)
    {
        if(s[i][1]=='A') return true;
        if(s[i][m]=='A') return true;
    }
    return false;
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        int tot=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            if(s[i][j]=='P') tot++;
        if(tot==n*m) printf("MORTAL\n");
        else if(tot==0) printf("0\n");
        else if(judge1()) printf("1\n");
        else if(judge2()) printf("2\n");
        else if(judge3()) printf("3\n");
        else printf("4\n");;
    }
}

E - Jeremy Bearimy
从边的角度考虑,如果要使总和尽可能的大,就是要使得边被路径穿过的次数最大那么一条连接u,v边被选的次数就使max(si[u],si[v]),贡献的价值是max(si[u],si[v])*wi

再考虑小的,如果一条边两边的点数都为偶数,那么只有使边两边相互配对即可,这条边就不需要被选,而除此之外的边只能被迫选择,如果采用的方案足够优秀,是不会有边重合的,因此一次dfs即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
ll ans,res;
int k,tot,head[N],si[N],nex[N<<1],to[N<<1],wi[N<<1];
void add(int u,int v,int w){to[++tot]=v;nex[tot]=head[u];head[u]=tot;wi[tot]=w;}
void dfs(int u,int p)
{
    si[u]=1;
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];if(v==p) continue;
        dfs(v,u);
        si[u]+=si[v];
        ans+=(ll)min(si[v],k-si[v])*wi[i];
        if(si[v]%2==0&&(k-si[v])%2==0) res-=wi[i];
    }
}
int main()
{
    int t;scanf("%d",&t);
    while(t--)
    {
        memset(head,0,sizeof(head));tot=0;
        scanf("%d",&k);
        k*=2;
        ans=res=0;
        for(int i=1;i<k;i++)
        {
            int u,v,w;scanf("%d%d%d",&u,&v,&w);
            add(u,v,w);add(v,u,w);
            res+=w;
        }
        dfs(1,0);
        printf("%lld %lld\n",res,ans);
    }
}

Codeforces Round #608 (Div. 2)
A - Suits

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll a,b,c,d,e,f;
    scanf("%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&e,&f);
    int t=min(a,d);
    ll ans=0;
    for(int i=0;i<=t;i++)
        ans=max(ans,i*e+min(min(b,c),d-i)*f);
    cout<<ans;
}

B - Blocks
无论怎么翻,两种颜色的奇偶性不变,因此线性的从左到右翻过去

#include<bits/stdc++.h>
using namespace std;
int n;
string s;
int main()
{
    cin>>n>>s;
    int ans1=0,ans2=0;
    for(int i=0;i<s.size();i++)
        if(s[i]=='B') ans1++;
        else ans2++;
    if((ans1&1)&&(ans2&1)){cout<<-1;return 0;}
    if(!(ans2&1))
        for(int i=0;i<s.size();i++)
        if(s[i]=='W') s[i]='B';
    else s[i]='W';
    queue<int>q;
    for(int i=0;i<s.size()-1;i++)
        if(s[i]=='B')
        {
            q.push(i+1);
            if(s[i+1]=='W') s[i+1]='B';
            else s[i+1]='W';
        }
    cout<<q.size()<<endl;
    while(!q.empty())
        cout<<q.front()<<' ',q.pop();
}

C - Shawarma Tent
对于一个点x,y,假设路径是sx,sy->sx,y->x,y,那么如果有另外一个点,如果走另外一个点不经过sx,sy->sx,y这条路,那么第二条路不会重合,反正很容易想到只要往sx,sy的上下左右四个方向加点就行

By Huah, contest: Codeforces Round #608 (Div. 2), problem: (C) Shawarma Tent, Accepted, #
 #include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n,sx,sy;
struct node
{
    int x,y;
}a[N];
int ans1,ans2,ans3,ans4;
int main()
{
    scanf("%d%d%d",&n,&sx,&sy);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a[i].x,&a[i].y);
        int x=a[i].x-sx,y=a[i].y-sy;
        if(y>0) ans1++;
        if(y<0) ans2++;
        if(x>0) ans3++;
        if(x<0) ans4++;
    }
    if(ans1>=ans2&&ans1>=ans3&&ans1>=ans4)
        printf("%d\n%d %d\n",ans1,sx,sy+1);
    else if(ans2>=ans1&&ans2>=ans3&&ans2>=ans4)
        printf("%d\n%d %d\n",ans2,sx,sy-1);
    else if(ans3>=ans1&&ans3>=ans2&&ans3>=ans4)
        printf("%d\n%d %d\n",ans3,sx+1,sy);
    else printf("%d\n%d %d\n",ans4,sx-1,sy);
}

D - Portals
首先倒推一个数组d[i],表示要想从这里跑到终点,那么至少要有d[i]的军力。然后想一想,如果在第i个港口,它在i+1~n的位置的时候也可以保护它,那么可以先不管它,到后面再保护也是一样的。那么就线性的去模拟,开一个优先队列,如果碰到一个在i位置可以保护,跑到后面就不能保护了,那么我只能选择保护这个港口了,当然和优先队列里面的比较,因为优先队列里的元素都是已经被保护的,但想一下,放弃前面一个小价值的城堡,保护后面一个价值更大的城堡,这样也是可以滴。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5005;
int n,m,k,a[N],b[N],c[N],d[N];
vector<int>v[N];
bool vis[N];
int vv[N];
struct node
{
    int x,id;
    node(int x=0,int id=0):x(x),id(id){}
    bool operator<(const node&o)const
    {
        return x>o.x;
    }
};
priority_queue<node>q;
pair<int,int>p[N];
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
    for(int i=1;i<=m;i++)
    {
        int x,y;scanf("%d%d",&x,&y);
        v[x].push_back(y);
        vv[y]++;
    }
    for(int i=1;i<=n;i++) vv[i]++;
    d[n]=a[n];
    for(int i=n-1;i>=1;i--)
        d[i]=max(a[i],d[i+1]-b[i]);
    if(k<d[1]){cout<<-1<<endl;return 0;}
    int now=k;
    for(int i=1;i<=n;i++)
    {
        vv[i]--;
        now=now+b[i];
        int tot=0;
        for(int j=0;j<v[i].size();j++)
        {
            vv[v[i][j]]--;
            if(!vv[v[i][j]])
                p[tot++]={c[v[i][j]],v[i][j]};
        }
        if(!vv[i])
            p[tot++]={c[i],i};
        sort(p,p+tot);
        for(int j=tot-1;j>=0;j--)
            if(!vis[p[j].second])
            {
                if(now>d[i+1])
                {
                    now--;
                    q.push(node(p[j].first,p[j].second));
                    vis[p[j].second]=true;
                }
                else if(!q.empty())
                {
                    if(q.top().x<p[j].first)
                    {
                        vis[q.top().id]=false;
                        q.pop();
                        q.push(node(p[j].first,p[j].second));
                        vis[p[j].second]=true;
                    }
                }
            }
    }
    ll ans=0;
    while(!q.empty())
        ans+=q.top().x,q.pop();
    printf("%lld\n",ans);
}

E Common Number
根据题意可以画出如图左边的一颗树,一个数的出现次数即为该结点以及该结点所有儿子结点的数量。

但是如图左边的树是不容易计算的,我们把数变一下形,转换成如图右边的二叉树,由于计算结点时出现多次的结点也只有一次的贡献

所以问题转换为在二叉树上进行计算,当要计算的数为x,如果x为奇数,就是普通二叉树上计算结点,如果x为偶数,显然计算的是x/2的结点数量减1。

在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k;
ll cal(ll x)
{
    ll tot=1,ans=0;
    while(x*2<=n)
    {
        ans+=tot;
        x*=2;tot*=2;
    }
    ans+=min(tot,n-x+1);
    return ans;
}
int main()
{
    scanf("%lld%lld",&n,&k);
    ll l=1,r=n/2,ans=1;
    while(l<=r)
    {
        ll m=l+r>>1;
        if(cal(m)-1>=k) ans=max(ans,m*2),l=m+1;
        else r=m-1;
    }
    l=0,r=(n-1)/2;
    while(l<=r)
    {
        ll m=l+r>>1;
        if(cal(m*2+1)>=k) ans=max(ans,m*2+1),l=m+1;
        else r=m-1;
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/Huah_2018/article/details/103562526
今日推荐