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;
}