CS R12 C(排序),D(思维(二进制)),E(计数,分类大讨论)

Round 12:
 
Problem C
题意:给出n个二元组(wi,hi) 若不存在j同时满足 wj>wi && hj>hi 则称j为合法的.
n<=1e5,wi,hi<=1e6 问有多少个合法二元组?
按w从小到大顺序排序,维护一个h非单调递增的单调栈 则最后栈中元素为合法的

wa! 相等的w 较大的h会淘汰掉小的h.排序时将相等的w h从大到小排序即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+20; 
struct node{
	int w,h;
}a[N];
bool cmp(node a,node b)
{
	if(a.w==b.w)
		return a.h>b.h;
	return a.w<b.w;
}
int top=0,sta[N];
int main()
{ 
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
		scanf("%d%d",&a[i].w,&a[i].h);
	sort(a+1,a+1+n,cmp);	
	for(int i=1;i<=n;i++)
	{
		while(top&&sta[top]<a[i].h)
			top--;
		sta[++top]=a[i].h;
	}
	cout<<top<<endl;
		
	return 0;
} 


Problem D
题意:Q次询问:a[i],b[i],x[i] Q<=1e5,a,b,x<=1e18.问有多少个a<=y<=b满足 y&x=x ?

先转为求[0,n]有多少个y满足y&x=x.对y进行分类,y二进制第一次和n不同的是在哪一位(或者说y和n的LCP长度)
因为y<=n 所以只能对n中二进制位数为1的反成0,后面是任意的 但是要求y&x=x 则预处理i之后的任意位.
注意点:若x第i位为1 n第i位为1时不能反成0 LCP只能继续增加. 
n第i位为0时 y和n的LCP长度最多为i-1,终止枚举.若没有停止标记 则说明y可以等于n
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e2+20; 
ll a,b,x,pre[N];
void init()
{
	int cnt=0;
	memset(pre,0,sizeof(pre));
	for(int i=0;i<62;i++)
	{
		pre[i]=cnt;
		cnt+=((x>>i)&1)^1;
	}
}
ll calc(ll n,ll x)
{
	ll ans=0;
	bool flag=false;
	for(int i=61;i>=0;i--)
	{
		int a=(n>>i)&1;
		int b=(x>>i)&1;
		if(a&&b)
			continue;
		if((!a)&&(b))
		{
			flag=true;
			break;
		}
		if((!a)&&(!b))
			continue;
		if(a&&(!b))
			ans+=(1ll<<pre[i]);
	}
	ans+=flag^1;//y==n;
	return ans;
}
int main()
{ 
	ios::sync_with_stdio(false);
	int Q;
	cin>>Q;
	while(Q--)
	{
		cin>>a>>b>>x;
		init();	
		cout<<calc(b,x)-calc(a-1,x)<<endl;
	}
	return 0;
} 



Problem E
题意:给出两个超大数a,b. b的位数为m,问[1,a]有多少个数,其前m个数字和后m个数字都等于b?.
n,m的位数<=1e6.

分两种情况来讨论.
第一种情况为前m个和后m个有重叠,最长重叠部分为fail[m].
第二种情况则没重叠 其长度>=2*m 
对于小于n的长度 m???m中间可以随便填10^num.
若长度正好等于n,则要判断前m个字符是否能为b(不能大于a的高位),

中间不超过限制时,在判断后面m个字符能否达到b.

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int N=2e6+20;
const ll mod=1e9+7; 
char a[N],b[N];
int pr[N]; 
ll ans,n,m;
vector<int> cmb;
void give_sol() {
    printf("%lld", ans % mod);
    exit(0);
}
ll get_limit(ll sp, ll pw10)
{
	ll res=0;
	for(int i=1;i<=m;i++)
	{
		if(a[i]<b[i])	return 0;
		if(a[i]>b[i])	return pw10;//中间任意
	}
	for(int i=1;i<=sp;i++)
		res=(res*10+a[i+m]-'0')%mod;//中间不超过限制
	res=(res+1)%mod;
	for(int i=1;i<=m;i++)
	{
		if(a[n-m+i]<b[i])
		{
			res=(res-1+mod)%mod;	
			break;
		}	
		if(a[n-m+i]>b[i])
			break;
	}
	return res;
}
bool check() 
{
    int i;
    
    for (i = 1; i <= m; i++) {
        if (a[i] < b[i]) return false;
        if (a[i] > b[i]) return true;
    }
    
    for (i = 1; i <= m; i++) {
        if (a[n - m + i] < b[i]) return false;
        if (a[n - m + i] > b[i]) return true;
    }
    
    return true;
}
void first_part()
{
	for(int i=0;i<cmb.size();i++)
	{
		int dim=2*m-cmb[i];
		if(dim<n)	ans++;
		if(dim>n)	give_sol();
		if(dim==n)
		{
			if(check())
				ans++;
			give_sol();
		}
	}
}
void second_part()
{
	ll pw10=1;
	for(int sp=0;2*m+sp<=n;sp++)
	{
		int len=2*m+sp;
		if(len<n)
			ans=(ans+pw10)%mod;
		else
			ans=(ans+get_limit(sp,pw10))%mod;
		pw10=(pw10*10ll)%mod;
	}
}
int main()
{ 
	scanf("%s%s",a+1,b+1);
	n=strlen(a+1);
	m=strlen(b+1);
 	pr[1] = 0;
 	int u,i;
    for (i = 2; i <= m; i++) {
        u = pr[i - 1];
        
        while (u && b[u + 1] != b[i]) u = pr[u];
        if (b[u + 1] == b[i]) u++;
        
        pr[i] = u;
    }
    for (u = m; u != 0; u = pr[u])
        cmb.pb(u);   
    first_part();
    second_part();
    give_sol();
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值