Codeforces Round #567 (Div. 2)

题目链接:http://codeforces.com/contest/1181

A Chunga-Changa

题意:两个人各a,b元,一个物品价值c元,求两个人一起最多可以买多少该物品,以及两人之间最小需要传递多少元。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int main()
{
	ll a,b,c;
	while(~scanf("%I64d%I64d%I64d",&a,&b,&c)){
		ll d=(a+b)/c;
		ll e;
		if((a/c+b/c)==d)
			e=0;
		else{
			
			e=min(c-a%c,c-b%c);
		}
		printf("%I64d %I64d\n",d,e);
	}
	return 0;
}

B Split a Number

题意:把一个无前缀0的数拆成两个无前缀0的数,将这两个数相加,求最小结果。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=100010;

char s[maxn];
char a[maxn],b[maxn];
char c[maxn],c2[maxn];
int n;
void cal2(char c[],char c2[])
{
	int m1=strlen(c),m2=strlen(c2);
	if(m1>m2) return;
	bool flag=0;
	for(int i=m1-1;i>=0;i--){
		if(c[i]!=c2[i]){
			if(c[i]>c2[i])
				flag=1;
			break;
		}
	}
	if(flag)
		memcpy(c,c2,sizeof(c2));
}
void cal(char c[],int m)// a+b->c
{
//	memset(a,0,sizeof(a));
//	memset(b,0,sizeof(b));
	for(int i=0;i<m;i++) a[i]=s[i];
	for(int i=m;i<n;i++) b[i-m]=s[i];
	int len1=m,len2=n-m;
	a[len1]=b[len2]='\0';
	int tot=0,flag=0,i=len1-1,j=len2-1;
	
//	printf("cur_m:%d a:%s b:%s\n",m,a,b);//
	while(i>=0&&j>=0){
		c[tot++]=(a[i]-'0'+b[j]-'0'+flag)%10+'0';
		flag=(a[i]-'0'+b[j]-'0'+flag)/10;
		i--;j--;
	}
	while(i>=0){
		c[tot++]=(a[i]-'0'+flag)%10+'0';
		flag=(a[i]-'0'+flag)/10;
		i--;
	}
	while(j>=0){
		c[tot++]=(b[j]-'0'+flag)%10+'0';
		flag=(b[j]-'0'+flag)/10;
		j--;
	}
	c[tot]='\0';
//	printf("cur_c:");
//	for(int i=tot-1;i>=0;i--) printf("%c",c[i]);
//	printf("\n");
}
void solve(int m1,int m2)
{
	while(s[m1]=='0'&&s[m2]=='0'){
		m1--;m2++;
	}
//	printf("m1:%d m2:%d\n",m1,m2);
	if(s[m1]=='0')
		cal(c,m2);
	else if(s[m2]=='0')
		cal(c,m1);
	else{
		cal(c,m1);
		cal(c2,m2);
		cal2(c,c2);
	}
}
int main()
{
	int m,m1,m2;
	while(~scanf("%d",&n)){
		scanf("%s",s);
		m=n/2;
		if(n%2==0){
			if(s[m]=='0'){
				m1=m;
				m2=m;
				solve(m1,m2);
			}else{
				cal(c,m);
			}
		}else{
			m1=m;m2=m+1;
			solve(m1,m2);
		}
		int len=strlen(c);
		for(int i=len-1;i>=0;i--) printf("%c",c[i]);
		printf("\n");
	}
	return 0;
}

C Flag

题意:给一个含nm个点的图,每个图最多有26个类型,分别为a-z;一个子图为flag图,如果该图由上中下三部分的类型点组成,三种类型两两互不相同,且其高度都相同,求一个nm的图,有多少个flag子图。
题解:st表,求原图s[][]的后缀之和suf[][],然后对于每一列的累积suf值,我们用st表,查询每一列最小值,对应每个从当前列开始,行标为[l,r]时flag图有多少个。为了方便,把矩阵转置来处理。详见代码。
参考思路来自 xyq0220

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1010;

char s[maxn][maxn];
int suf[maxn][maxn];
int st[maxn][maxn][20];
int n,m;
void init()
{
	for(int i=1;i<=m;i++)
		for(int k=1;(1<<k)<=n;k++)
			for(int j=1;j+(1<<k)-1<=n;j++)
				st[i][j][k]=min(st[i][j][k-1],st[i][j+(1<<k-1)][k-1]);
}
int cal(int i,int l,int r)
{
	int m=log2(r-l+1);
	return min(st[i][l][m],st[i][r-(1<<m)+1][m]);
}
int main()
{
	while(~scanf("%d%d",&n,&m)){
		for(int i=1;i<=n;i++)
			scanf("%s",s[i]+1);
		for(int i=1;i<=n;i++){
			suf[i][m+1]=0;
			for(int j=m;j>=1;j--){
				if(s[i][j]==s[i][j+1])
					suf[i][j]=suf[i][j+1]+1;
				else
					suf[i][j]=1;
			}
		}
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++)
				st[j][i][0]=suf[i][j];
		init();
		ll ans=0;
		vector<int> ve;
		for(int i=1;i<=m;i++){
			ve.clear();
			for(int j=1;j<=n;j++){
				int k=j;
				while(s[k][i]==s[j][i]) k++;
				ve.push_back(k-j);
				j=k-1;
			}
			int k=1;
			for(int j=0;j+2<ve.size();j++){
				if(ve[j]>=ve[j+1]&&ve[j+1]<=ve[j+2]){
					int l=k+ve[j]-ve[j+1],r=k+ve[j]+2*ve[j+1]-1; 
					ans+=1LL*cal(i,l,r);
				}
				k+=ve[j];
			}
		}
		printf("%I64d\n",ans);
	}
	return 0;
}

D Irrigation

//By natofp, contest: Codeforces Round #567 (Div. 2), problem: (D)

//By natofp, contest: Codeforces Round #567 (Div. 2), problem: (D) Irrigation
#include <iostream>
#include <bits/stdc++.h>

using namespace std;

int n,m,q;
const int nax=5e5+5;
int a[nax];
long long int p[nax];
long long int k;
vector<pair<int,int> > xd;
int ans[nax];
const int roz=(1<<21);

int tree[roz];

long long int ile(int l,int r)
{
    if(l==0) return p[r];
    return p[r]-p[l-1];
}

void add(int pos,int val)
{
    pos+=roz/2;
    while(pos>=1)
    {
        tree[pos]++;
        pos/=2;
    }
}

bool czy(long long int x)
{
    //czy pefix[0....x] BEDZIE ROWNY;
    long long int naj=xd[x].first;
    naj*=(x+1);
    naj-=ile(0,x);
    if(naj>=k) return false;
    return true;
}

int kty(int z)
{
    int pos=1;
    while(1)
    {
        if(pos>=roz/2) return pos-roz/2;
        if(tree[pos*2]<z)
        {
            z-=tree[pos*2];
            pos=pos*2+1;
        }
        else
        {
            pos*=2;
        }

    }
}


int main()
{
    ios_base::sync_with_stdio(0);
    cin.tie(0);
    memset(tree,0,sizeof tree);
    cin>>n>>m>>q;
    memset(a,0,sizeof a);
    memset(p,0,sizeof p);
    for(int i=1;i<=n;i++)
    {
        int x; cin>>x;
        a[x]++;
    }
    for(int i=1;i<=m;i++)
    {
        xd.push_back({a[i],i});
    }
    sort(xd.begin(),xd.end());
    p[0]=xd[0].first;
    for(int i=1;i<m;i++)
    {
        p[i]=p[i-1]+xd[i].first;
    }
    vector<pair<long long int,int> > zap;
    for(int i=0;i<q;i++)
    {
        long long int x; cin>>x;
        zap.push_back({x,i});
    }
    sort(zap.begin(),zap.end());
    int wsk=-1;
    for(int i=0;i<q;i++)
    {
        k=zap[i].first;
        k-=n;
        long long int lo,hi;
        lo=0;
        hi=m-1;
        while(lo+1<hi)
        {
            long long int mid=(lo+hi)/2;
            if(czy(mid)) lo=mid;
            else hi=mid;
        }
        long long int res;
        if(czy(hi)) res=hi;
        else res=lo;
        //cout<<res<<endl;
        // prefix[0...res] jest ROWNY;
        long long kappa=xd[res].first;
        kappa*=(res+1);
        kappa-=ile(0,res);
        k-=kappa;
        long long int idx=(k%(res+1));
        if(idx==0) idx+=res+1;
        while(wsk+1<=res)
        {
            wsk++;
            add(xd[wsk].second,1);
        }
        ans[zap[i].second]=kty(idx);
    }
    for(int i=0;i<q;i++) cout<<ans[i]<<"\n";
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值