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