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

来源:互联网 发布:nextdate函数java代码 编辑:程序博客网 时间:2024/05/06 07:02
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_backusing 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;elseans=(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;} 


阅读全文
0 0
原创粉丝点击