Educational Codeforces Round 110 VP

为什么一VP就能过这么多…

题目链接

https://codeforces.com/contest/1535

A 题意

四个数,12比34比之后再比。如果决赛是最强的俩人比就是公平,问是否公平

A 思路

最强次强别再第一轮相遇即可

A 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
//#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=400505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
	void solve(){
		int ma=-inf,mi=inf,in1,in2;
        for(int i=0;i<4;i++){
            int t;
            cin>>t;
            if(t>ma){
                mi=ma,in2=in1;
                ma=t,in1=i;
            }
            else if(t>mi){
                mi=t,in2=i;
            }
        }
        if((in1^1)==in2){
            cout<<"NO"<<endl;
        }
        else{
            cout<<"YES"<<endl;
        }
	}
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
		cin>>tn;
		while(tn--){
			solve();
		}
	} 
						
B 题意

排序数组,让数对ij满足i<j,gcd(a[i],2a[j])!=1最多。

B 思路

注意那个2a[j]很有意思,我们贪心处理,所有偶数扔最前面,他们和后面gcd一定比>=2,这部分是个等差求和,之后就可以剔除掉它们了。剩下奇数,那么其实gcd(a[i],2a[j])和gcd(a[i],a[j])也就没有区别了,那么排序也就无所谓了,直接两个枚举求就好了。

B 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=400505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    vector<int>v;
    int ans;
	void solve(){
        ans=0;
        int t=0,k=0;
        v.clear();
        cin>>n;
        for(int i=1;i<=n;i++){
            int w;
            cin>>w;
            if(w%2){
                v.push_back(w);
                t++;
            }
            else{
                k++;
            }
        }
        ans=k*(2*t+k-1)/2;
        n=v.size();
        for(int i=0;i<n;i++)
            for(int j=i+1;j<n;j++)
                if(__gcd(v[i],v[j])!=1) ans++;
        cout<<ans<<endl;
	}
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
		cin>>tn;
		while(tn--){
			solve();
		}
	} 
						
C 题意

一个unstable串定义为01010101,10101010这种不存在00和11的01串。一个美丽串定义为01?的三元串,且?可以填0或者1使得这个串变成unstable串。问给出的串有几个美丽子串。子串定义为去前缀后缀的原串

C 思路

我们统计每个元素为最左端的情况下子串数量,这样总和就是不重不漏所有子串了。

我们统计每个元素最远能延展的最右端下标,比如0010,第一个0只能延展到2,因为00不合法,第二个0可以延展到5,因为后面全合法。容易发现上文提到的子串数量就是这个新统计量-自己下标。对于?我们暂时跳过,如果是别的元素延展过程中遇到了?,默认其合法,继续延展。统计完后我们把?的统计量设为他右边元素的统计量即可。比如?11,我们先跳过?,2号位置1的统计量是3,3号是4,我们再回头把1号?的统计量设为3.答案就是(4-3)+(3-2)+(3-1)。

对于维护这个统计量,我们线性扫一遍就可以了,我这里用了个比较麻烦的实现,属于是比赛的时候紧张了。一会看看有没有必要重写下。

C 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=400505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int a[maxn];
    int b[maxn],d[maxn];
    vector<int>v;
    int ans;
	void solve(){
        ans=0;
        string s;
        cin>>s;
        n=s.size();
        for(int i=0;i<=n;i++)   b[i]=d[i]=0;
        s='z'+s;
        for(int i=1;i<=n;i++){
            if(s[i]=='?')   continue;
            int t=s[i]-'0';
            b[i]=(t+i)%2;
        }
        stack<int>sa;
        for(int i=1;i<=n;i++){
            if(s[i]=='?')   continue;
            if(sa.empty()||b[sa.top()]==b[i])
                sa.push(i);
            else{
                while(sa.size()){
                    int now=sa.top();sa.pop();
                    d[now]=i;
                }
                sa.push(i);
            }
        }
        while(sa.size()){
            int now=sa.top();sa.pop();
            d[now]=n+1;
        }
        d[n]=n+1;
        for(int i=n;i;i--){
            if(!d[i])
                d[i]=d[i+1];
            ans+=d[i]-i;
        }
        cout<<ans<<endl;
	}
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
		cin>>tn;
		while(tn--){
			solve();
		}
	} 
						
D 题意

类似A的竞赛,只不过初始队伍变多,有2^(k+1)支队伍,那么也就需要k轮竞赛。给你一个01?串,按坐标代表第i场比赛输赢,0代表小队赢,1代表大队赢,?代表都可能。f(s)意为在s情况下有几个队有机会赢,q次询问改变s某一位,每次操作完输出f(s)

D 思路

k才18,几十万的数量级,我们直接dp[I]代表i场比赛能产生几个胜者。x,y代表产生i比赛的两个前置比赛,有 d p ( i ) = { d p ( x ) , s [ i ] = 0 d p ( y ) , s [ i ] = 1 d p ( x ) + d p ( y ) , s [ i ] = ? dp(i)=\left\{ \begin{aligned} dp(x),s[i]=0\\ dp(y),s[i]=1\\ dp(x)+dp(y),s[i]=? \end{aligned} \right. dp(i)=dp(x),s[i]=0dp(y),s[i]=1dp(x)+dp(y),s[i]=?
推一下由i找到xy和由xy找到i的公式,每次修改改掉s[i]之后暴力传递一下即可,复杂度应该是qk的。

D 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=1000505;
	const int inf=0x3f3f3f3f;
	int n,m,k;
    int dp[maxn];
    string s;
    int t,fi;
    inline int s1(int x){
        return max(2*(x-1-t)+1,0ll);
    }
    inline int s2(int x){
        return max(2*(x-1-t)+2,0ll);
    }
    inline int fa(int x){
        return (x+1)/2+t;
    }
    void up(int x){
        if(x>fi)    return ;
        if(s[x]=='?'){
            dp[x]=dp[s1(x)]+dp[s2(x)];
        }
        else if(s[x]=='0'){
            dp[x]=dp[s1(x)];
        }
        else
            dp[x]=dp[s2(x)];
        up(fa(x));
    }
    void change(int x,char c){
        if(s[x]==c)
            return ;
        s[x]=c;
        up(x);
    }
	void solve(){
        
        for(int i=0;i<maxn;i++) dp[i]=1;
        cin>>k;
        t=pow(2,k-1);
        fi=pow(2,k)-1;
        cin>>s;
        s='z'+s;
        for(int i=1;i<=fi;i++){
            if(s[i]=='?')
                up(i);
        }
        //for(int i=1;i<=t;i++)
        //    up(i);
        cin>>m;
        while(m--){
            int a;
            char b;
            cin>>a>>b;
            change(a,b);
            cout<<dp[fi]<<endl;
        }
	}
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
		while(tn--){
			solve();
		}
	} 
						
E 题意

给你一颗树,初始只有根。每个点有a,c两个值,代表这个点有多少金子,每吨多少钱。给出q个操作如下

  1. 插入一个新结点,满足新节点金价在所有父节点中最贵
  2. 给出结点号和需求量,在根到这个结点中买金子,问最多能买多少,花多少钱。要求花的钱最少。
E 思路

注意子节点金子更贵。所以我们策略一定是优先买根节点近的金子,在链上操作,我们直接搞一个倍增找还有金子的父节点,能买就全买,直到买完或者买完当前节点都不够为止。
第一道树上倍增,有点意思,一会学学。

E 代码
#include<cstdio>
#include<iostream>
#include<iomanip>
#include<map>
#include<unordered_map>
#include<string>
#include<queue>
#include<stack>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib> 
#include<chrono>
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define endl "\n"
#define int long long
//#define double long double
using namespace std;
	typedef long long ll;
	const int maxn=400505;
	const int inf=0x3f3f3f3f;
	int n,m,k,q;
    int arr[maxn];
    int cost[maxn],have[maxn];
    int fa[maxn][25];
    int get(int x){
        for(int i=24;~i;i--){
            if(fa[x][i]&& have[fa[x][i]])   x=fa[x][i];
        }
        return x;
    }
	void solve(){
		cin>>q>>have[1]>>cost[1];
        for(int i=2;i<=q+1;i++){
            int op,a,b,c,d;
            cin>>op;
            if(op==1){
                cin>>a>>b>>c;
                a++;
                have[i]=b,cost[i]=c;
                fa[i][0]=a;
                for(int j=1;j<25;j++)
                    fa[i][j]=fa[fa[i][j-1]][j-1];
            }
            else{
                cin>>a>>b;//a到0买b吨
                a++;
                int cc=0,hh=0;
                while(1){
                    int x=get(a);
                    if(!have[x])  break;
                    int can_buy=min(b,have[x]);
                    hh+=can_buy;
                    have[x]-=can_buy;
                    cc+=cost[x]*can_buy;
                    b-=can_buy;
                    if(!b||x==a)    break;//买够了,或者把自己都买空了。
                }
                cout<<hh<<' '<<cc<<endl;
                cout.flush();
            }
        }
	}
	signed main(){
        IOS
		#ifndef ONLINE_JUDGE
		    freopen("IO\\in.txt","r",stdin);
		    freopen("IO\\out.txt","w",stdout);
        #endif
		int tn=1;
		while(tn--){
			solve();
		}
	} 
						
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值