蓝桥杯刷题笔记

2019年C++A组

E RSA解密
若d * e和(p-1) * (q-1)互质,那么说明d * e=1(mod (p-1) * (q-1) ),那么e为d的逆元,应为(p-1) * (q-1)不是指数,所以不能用费马小定理要用扩展欧几里得。求出e后,用公式X=C^e mod n就可以解出X了。然后说说怎么求p和q,对sqrt(n)以内的暴力,解出来的就是p和q。

# include <bits/stdc++.h>
using namespace std;

typedef long long LL;
inline LL mul(LL a,LL b,LL p)
{
    LL c=(long double)a/p*b;
    LL res=(unsigned long long)a*b-(unsigned long long)c*p;
    return (res+p)%p;
}
inline LL quick_pow(LL a,LL b,LL p)
{
    LL ret=1;
    while(b)
    {
        if(b&1) ret=mul(ret,a,p);
        a=mul(a,a,p);
        b>>=1;
    }
    return ret;
}
inline LL exgcd(LL a,LL b,LL &x,LL &y)
{
    if(b==0) {x=1,y=0; return a; }
    LL d=exgcd(b,a%b,x,y);
    LL z=x;x=y;y=z-y*(a/b);
    return d;
}
int main()
{
    LL n=1001733993063167141,d=212353,C=20190324,p,q;
    for(LL i=3;i*i<n;i+=2){
        if(n%i==0){
            p=i;
            q=n/i;
            break;
        }
    }
    LL m=(p-1)*(q-1);
    LL xx=0,yy=0;
    exgcd(d,m,xx,yy);
    if(xx<0) xx+=m;
    LL e=xx;
    LL x=quick_pow(C,e,n);
    printf("%lld\n",x);

    return 0;
}

G外面店优先级

# include <bits/stdc++.h>
using namespace std;

const int MAcXN=1e5+100;
struct dd{
    int ts,id;
}DD[MAXN];
int S[MAXN];
int f[MAXN];
int cmp(dd a,dd b)
{
    if(a.id==b.id) return a.ts<b.ts;
    return a.id<b.id;
}
int main()
{
    int N,M,T; scanf("%d%d%d",&N,&M,&T);

    for(int i=1;i<=M;++i){
        scanf("%d%d",&DD[i].ts,&DD[i].id);
    }
    sort(DD+1,DD+M+1,cmp);
    int pre=0;
    for(int i=1;i<=M;++i){
        if(i==1||DD[i].id==DD[i-1].id){

        }else{
            if(T>DD[i-1].ts) S[DD[i-1].id]=max(0,S[DD[i-1].id]-(max(0,T-DD[i-1].ts)));
            if(S[DD[i-1].id]<=3) f[DD[i-1].id]=0;
            if(S[DD[i-1].id]>5) f[DD[i-1].id]=1;
            pre=0;
        }
        S[DD[i].id]=max(0,S[DD[i].id]-(max(0,DD[i].ts-pre-1)));
        S[DD[i].id]+=2;
        pre=DD[i].ts;
    }
    if(T>DD[M].ts) S[DD[M].id]=max(0,S[DD[M].id]-(max(0,T-DD[M].ts)));
    if(S[DD[M].id]<=3) f[DD[M].id]=0;
    if(S[DD[M].id]>5) f[DD[M].id]=1;
    int now=0,ans=0;
    for(int i=1;i<=N;++i){
        now=now-T+S[i]*3;
        if(now>5) ans++;
    }
    printf("%d\n",ans);

    return 0;
}

H修改数组
首先想到可以用【l,r】区间的长度和区间标记的个数来判断有没有能够可以用的数。对一个数在数组中已经存在,那么就add(a[i],1)来标记它,然后判断的时候如果sum( r) -sum(l-1) >= 区间长度,那么久说明该区间内没有可以用的数。根据这个可以写出判断函数check。然后边读入边处理,对于一个数如果之前已经出现过,那么根据题意就是需要修改的,那么可以用二分查找来查找这个值。有了该位置要填的值之后,add(ans[i],1),f[ans[i]]=1.

#include <bits/stdc++.h>
using namespace std;

const int MAXN=1e5+100;
const int MAXX=1e6+100;
int c[MAXN],a[MAXN];
int lowbit(int x){return x&(-x);}
void add(int x,int y,int n)
{
    for(int i=x;i<=n;i+=lowbit(i)) c[i]+=y;
    return ;
}
int sum(int x)
{
    int ans=0;
    for(int i=x;i;i-=lowbit(i)) ans+=c[i];
    return ans;
}
int check(int k,int pre)
{
    int cnt=k-pre+1;
    if((sum(k)-sum(pre-1))<cnt) return 1;
    return 0;
}
int f[MAXX],ans[MAXN];
int main()
{
    int N; scanf("%d",&N);
    for(int i=1;i<=N;++i){
        scanf("%d",&a[i]);
        if(!f[a[i]]){
            ans[i]=a[i];
            f[a[i]]=1;
            add(a[i],1,N);
        }else{
            int l=a[i],r=1e6+10;
            int mid;
            while(r-l>1){
                mid=(l+r)>>1;
                if(check(mid,a[i])) r=mid;
                else l=mid;
            }
            ans[i]=r;
            add(r,1,N);
            f[r]=1;
        }
    }

    for(int i=1;i<=N;++i) printf("%d%c",ans[i],(i==N)?'\n':' ');

    return 0;
}

I糖果
状压DP,首先对一袋糖果标记这代糖果能有哪些口味的糖果,并且标记一些口味的糖果能够到达的袋数,dp[ss]记录袋数,然后对每一袋糖果所能有的口味,和1~1<<m-1所有的口味进行组合,看哪些组合两个都能到,并标记最小袋数。最后输出1<<m-1的袋数即可。

# include <bits/stdc++.h>
using namespace std;

const int MAXN=1<<20;
int s[MAXN],dp[MAXN];
int main()
{
    memset(dp,-1,sizeof(dp));
    int N,M,K; scanf("%d%d%d",&N,&M,&K);
    for(int i=1;i<=N;++i){
        int ss=0,t;
        for(int j=1;j<=K;++j){
            scanf("%d",&t);
            ss=ss|(1<<(t-1));
        }
        s[i]=ss;
        dp[ss]=1;
    }
    for(int i=1;i<=N;++i){
        for(int j=1;j<(1<<M);++j){
            if(dp[j]==-1) continue;
            if(dp[j|s[i]]==-1) dp[j|s[i]]=dp[j]+dp[s[i]];
            else dp[j|s[i]]=min(dp[j|s[i]],dp[j]+dp[s[i]]);
        }
    }
    printf("%d\n",dp[(1<<M)-1]);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值