Educational Codeforces Round 72 (Rated for Div. 2) ABCD

Educational Codeforces Round 72 (Rated for Div. 2)

本场链接


Problem A

题意:a点物理,b点智力,c个技能点,技能点加完的情况下,物理大于智力的情况有多少种

思路:我们只需要a和b的相对差值a-b,然后先把c全部加到a上去,每次移到b,a-b+c -2-2-2,所以不管其他什么的话有(a-b+c+1)/2种,然后不能超过c+1种,因为技能点分配有这么多种,还有技能点为0时的特判,a>b?1:0。

#include
    
using namespace std;
    
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define fi first
#define se second
#define pb push_back
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _r(const int&x){scanf("%d",&x);}
void _r(const ll&x){scanf("%I64d",&x);}
void _r(const char*x){scanf("%s",x);}
void R(){}
template<class T,class... U>void R(const T&head,const U&...tail){_r(head);R(tail...);}
void _w(const char x){putchar(x);}
void _w(const char*x){printf("%s",x);}
void _w(const int x){printf("%d",x);}
void _w(const ll x){printf("%I64d",x);}
void _w(const double x){printf("%.6f",x);}
void W(){}
template<class T,class...U>void W(const T&head,const U&...tail){_w(head);putchar(sizeof...(tail)?' ':'\n');W(tail...);}
const ll mod = 1e9+7;
ll fp1(ll a,ll b){ll ans=1;while (b){if(b&1)ans*=a;b>>=1;a*=a;}return ans;}
ll fp2(ll a,ll b){ll ans=1;while (b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll Read(){
    ll res=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')flag = -1;ch = getchar();}
    while (ch>='0' && ch<='9'){res = res*10+ch-'0';ch = getchar();}
    return res*flag;
}
    
const int N = 2e5+5;
    
    
int main()
{
    ll a,b,c;
    duozu{
        R(a,b,c);
        W(max(min((a-b+c+1)/2,c+1),a>b?1LL:0LL));
    }
    return 0;
}

Problem B

题意:生命值x,有n种造成伤害方式,造成di点伤害后恢复hi点生命值,询问最少几次打死

思路:只要生命值低于伤害最高技能就到斩杀线了,因此对于没到斩杀线的时候我们使用掉血最快的技能。当没有办法一拳超人并且所有技能收益都为负的时候无法击杀boss。

#include
    
using namespace std;
    
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define fi first
#define se second
#define pb push_back
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _r(const int&x){scanf("%d",&x);}
void _r(const ll&x){scanf("%I64d",&x);}
void _r(const char*x){scanf("%s",x);}
void R(){}
template<class T,class... U>void R(const T&head,const U&...tail){_r(head);R(tail...);}
void _w(const char x){putchar(x);}
void _w(const char*x){printf("%s",x);}
void _w(const int x){printf("%d",x);}
void _w(const ll x){printf("%I64d",x);}
void _w(const double x){printf("%.6f",x);}
void W(){}
template<class T,class...U>void W(const T&head,const U&...tail){_w(head);putchar(sizeof...(tail)?' ':'\n');W(tail...);}
const ll mod = 1e9+7;
ll fp1(ll a,ll b){ll ans=1;while (b){if(b&1)ans*=a;b>>=1;a*=a;}return ans;}
ll fp2(ll a,ll b){ll ans=1;while (b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll Read(){
    ll res=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')flag = -1;ch = getchar();}
    while (ch>='0' && ch<='9'){res = res*10+ch-'0';ch = getchar();}
    return res*flag;
}
    
const int N = 110;
    
int d[N],h[N];
    
    
int main()
{
    int n,x;
    duozu{
        int maxx = 0,maxfi = 0;
        bool flag = false;
        R(n,x);
        for0(i,0,n) {R(d[i],h[i]),maxx = max(maxx,d[i]-h[i]),maxfi = max(maxfi,d[i]);if (d[i]>h[i]) flag = true;}
        if (maxfi>=x){W(1);continue;}
        if (!flag){puts("-1");continue;}
        int ans = 1;
        x -= maxfi;
        ans += x%maxx==0?x/maxx:x/maxx+1;
        W(ans);
    }
    return 0;
}

Problem C

题意:输入一个01串,任意选取区间如果区间内的01串对应二进制数大小等于位数(前导0补充)就记一次到答案,询问记了几次

思路:发现串只有2e5位那么能表示出的最大的数也就2e5,2e5对应的需要区间也就18位,枚举超过18位的100%亿不能成功计数因为没有这么多前导0,所以最多暴力枚举1~18区间长度然后枚举起点,必须只计算每种长度下并且没有前导0的状况,也就是说起点是0的直接跳过,否则有前导0会在枚举各个长度重复计算,然后前导0个数预处理一下就行,区间后移计算数的大小的时候每次后移一位获取下一个区间代表的数字可以O(1)实现

#include
    
using namespace std;
    
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define fi first
#define se second
#define pb push_back
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _r(const int&x){scanf("%d",&x);}
void _r(const ll&x){scanf("%I64d",&x);}
void _r(const char*x){scanf("%s",x);}
void R(){}
template<class T,class... U>void R(const T&head,const U&...tail){_r(head);R(tail...);}
void _w(const char x){putchar(x);}
void _w(const char*x){printf("%s",x);}
void _w(const int x){printf("%d",x);}
void _w(const ll x){printf("%I64d",x);}
void _w(const double x){printf("%.6f",x);}
void W(){}
template<class T,class...U>void W(const T&head,const U&...tail){_w(head);putchar(sizeof...(tail)?' ':'\n');W(tail...);}
const ll mod = 1e9+7;
ll fp1(ll a,ll b){ll ans=1;while (b){if(b&1)ans*=a;b>>=1;a*=a;}return ans;}
ll fp2(ll a,ll b){ll ans=1;while (b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll Read(){
    ll res=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')flag = -1;ch = getchar();}
    while (ch>='0' && ch<='9'){res = res*10+ch-'0';ch = getchar();}
    return res*flag;
}
    
const int N = 2e5+5;
char s[N];
int bf[N];
    
int main()
{
    duozu{
        R(s);
        int len = strlen(s);
        int ed = 0;
        while (len > (1LL<<(ed))) ed++;//左移ed位,实际ed+1位
        bf[0] = 0;
        for0(i,1,len) bf[i] = s[i-1]=='0'? bf[i-1]+1:0;
        ll ans = 0;
        for1(i,1,ed+1){//区间长度
            int l=1<<(i-1),r = (1<<i)-1;
            //W("i =",i);
            int num = 0;
            int bi = 1;
            rof1(j,i-1,0){if (s[j]=='1') num+=bi;bi<<=1;}
            //W(num);
            if (num>=l && num<=r && bf[0] >= num-i) ans++;  
            for0(st,1,len-i+1){
                if (s[st-1]=='1') num -= (1<<(i-1));
                num<<=1;
                num+=s[st+i-1]-'0';
                //W(num);
                if (num>=l && num<=r && bf[st]>=num-i) ans++;
            }
        }
        W(ans);
    }
    return 0;
}

Problem D

题意:有向图,给边,染色,在不出现‘‘一个环上的边颜色都一样’’的情况下询问最少需要的颜色以及按顺序(即边的输入顺序)输出每条边的颜色

思路:碰到图无脑往dfs方向靠拢。于是开始dfs。对于碰到还未访问过的点的边染为1,很显然,因为这些边连起来是一棵有向树,但是还存在其他的边,这些边去向已经访问过的边,这里分为两种,如果在当前的dfs路径(就是从根到当前起点的路径)上,那么这种边染色为2,为什么呢因为这条边显然退回到当前这个起点的某个祖先,而那个祖先又可以到当前起点所以就形成环了,另外还有不在dfs路径上的那随便连都没事因为没有办法到达当前起点祖先,也就没有办法形成环,假设可以形成环的话那么那个点必定有路径到当前的起点,那么必定在同一条路径,与条件相悖。
总结:理解只有回到dfs路径上的边才能形成环

#include
    
using namespace std;
    
#define ll long long
#define for1(i,a,b) for (int i=(a);i<=(b);i++)
#define for0(i,a,b) for (int i=(a);i<(b);i++)
#define rof1(i,a,b) for (int i=(a);i>=(b);i--)
#define rof0(i,a,b) for (int i=(a);i>(b);i--)
#define fi first
#define se second
#define pb push_back
#define duozu int __T;scanf("%d",&__T);for1(ica,1,__T)
void _r(const int&x){scanf("%d",&x);}
void _r(const ll&x){scanf("%I64d",&x);}
void _r(const char*x){scanf("%s",x);}
void R(){}
template<class T,class... U>void R(const T&head,const U&...tail){_r(head);R(tail...);}
void _w(const char x){putchar(x);}
void _w(const char*x){printf("%s",x);}
void _w(const int x){printf("%d",x);}
void _w(const ll x){printf("%I64d",x);}
void _w(const double x){printf("%.6f",x);}
void W(){}
template<class T,class...U>void W(const T&head,const U&...tail){_w(head);putchar(sizeof...(tail)?' ':'\n');W(tail...);}
const ll mod = 1e9+7;
ll fp1(ll a,ll b){ll ans=1;while (b){if(b&1)ans*=a;b>>=1;a*=a;}return ans;}
ll fp2(ll a,ll b){ll ans=1;while (b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans;}
ll Read(){
    ll res=0,flag=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if (ch=='-')flag = -1;ch = getchar();}
    while (ch>='0' && ch<='9'){res = res*10+ch-'0';ch = getchar();}
    return res*flag;
}
    
const int N = 5e3+5;
    
bool cyc;
int col[N];
int res[N];
vector<pair<int,int> >e[N];
    
void dfs(int v){
    col[v] = 1;
    for (auto a:e[v]){
        int to = a.fi,id = a.se;
        if (col[to]==0){
            dfs(to);
            res[id] = 1;
        }
        else if (col[to]==2) res[id] = 1;
        else {
            res[id] = 2;
            cyc = true;
        }
    }
    col[v] = 2;
}
    
int main()
{
    int n,m,u,v;
    while (~scanf("%d %d",&n,&m)){
        cyc = false;
        for1(i,1,n) e[i].clear(),col[i] = 0;
        for1(i,1,m) R(u,v),e[u].pb(make_pair(v,i));
        for1(i,1,n){
            if (col[i]==0) dfs(i);
        }
        W(cyc?2:1);
        for1(i,1,m) printf("%d ",res[i]);
        W("");
    }
    return 0;
}

Problem E

题意

思路



Problem F

题意

思路


你可能感兴趣的:(Codeforces补题)