题面:https://www.cnblogs.com/Juve/articles/11479415.html
T1:高精度gcd,其实不用写高精度取模,gcd还有一种求法
int gcd(int a,int b){ if(a==b) return a; if(a%2==0&&b%2==0) return 2*gcd(a/2,b/2); if(a%2==0) return gcd(a/2,b); if(b%2==0) return gcd(a,b/2); if(a<b) swap(a,b); return gcd(a-b,b); }
然后愉快地AC
#include<iostream> #include<cstdio> #include<cstring> #define int long long #define re register using namespace std; int t,la,lb,c[105]; char a[105],b[105]; struct bigint{ int m[105]; bigint(){memset(m,0,sizeof(m));} inline friend void operator *= (bigint &a,re int b){ int x=0; for(re int i=1;i<=a.m[0];i++){ re int y=a.m[i]*b+x; a.m[i]=y%10; x=y/10; } while(x){ a.m[++a.m[0]]=x%10; x/=10; } } inline friend void operator /= (bigint &a,re int b){ re int x=0; for(re int i=a.m[0];i>=1;i--){ x+=a.m[i]; a.m[i]=x/b; x%=b; x*=10; } while(a.m[a.m[0]]==0&&a.m[0]>1) a.m[0]--; } inline friend bigint operator - (bigint a,bigint b){ bigint c; re int i=1; while((i<=a.m[0])||(i<=b.m[0])){ if(a.m[i]<b.m[i]){ a.m[i]+=10; a.m[i+1]--; } c.m[i]=a.m[i]-b.m[i]; i++; } while(c.m[i]==0&&i>1) i--; c.m[0]=i; return c; } inline friend bool operator >= (bigint a,bigint b){ if(a.m[0]>b.m[0]) return 1; if(a.m[0]<b.m[0]) return 0; for(int i=a.m[0];i>=1;--i){ if(a.m[i]==b.m[i]) continue; return a.m[i]>b.m[i]; } return 1; } inline friend bool operator == (bigint a,bigint b){ int p=a.m[0],q=b.m[0]; if(p!=q) return 0; for(int i=1;i<=p;++i){ if(a.m[i]!=b.m[i]) return 0; } return 1; } inline friend void print(bigint a){ for(re int i=a.m[0];i>=1;i--) printf("%lld",a.m[i]); puts(""); } }n,m; bool judge(bigint a){ int p=a.m[1]; //cout<<p<<endl; if(p%2==0) return 1; return 0; } bool check(bigint a,bigint b){ //print(a),print(b); if(a==b){ if(a.m[0]==1&&a.m[1]==1) return 1; else return 0; } bool p=judge(a),q=judge(b); //cout<<p<<' '<<q<<endl; if(p&&q) return 0; if(p){ a/=2; return check(a,b); } if(q){ b/=2; return check(a,b); } if(!(a>=b)) swap(a,b); return check(a-b,b); } int gcd(int a,int b){ if(a==b) return a; if(a%2==0&&b%2==0) return 2*gcd(a/2,b/2); if(a%2==0) return gcd(a/2,b); if(b%2==0) return gcd(a,b/2); if(a<b) swap(a,b); return gcd(a-b,b); } signed main(){ scanf("%lld",&t); while(t--){ memset(n.m,0,sizeof(n.m)); memset(m.m,0,sizeof(m.m)); scanf("%s %s",a+1,b+1); la=strlen(a+1),lb=strlen(b+1); n.m[0]=la,m.m[0]=lb; for(int i=1;i<=la;++i) n.m[la-i+1]=a[i]-'0'; for(int i=1;i<=lb;++i) m.m[lb-i+1]=b[i]-'0'; if(check(n,m)==1) puts("Yes"); else puts("No"); } return 0; }
T2:
正解$O(n)$,数状数组卡常可A
$sum_i$表示前缀和
我们对于每一个i,求出$sum_i-sum_{j-1}>frac{i-j+1}{2}(j<i)$的数量
然后就转化成了$2sum_i-i>2sum_{j-1}-(j-1)$,然后数状数组即可
然后用总区间减去不合法的即可
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define re register using namespace std; const int MAXN=5e6+5; int n,sum0[MAXN],sum1[MAXN],sum2[MAXN],sum[MAXN]; char a[MAXN],ch; long long ans=0; struct BIT_tree{ int c[MAXN*3]; inline int lowbit(re int x){ return x&-x; } inline void add(re int pos){ //cout<<pos<<' '<<val<<endl; while(pos<=2*n){ ++c[pos]; pos+=lowbit(pos); //cout<<pos<<endl; } } inline int query(re int pos){ re int res=0; while(pos>0){ res+=c[pos]; pos-=lowbit(pos); } return res; } }tr[3]; signed main(){ //freopen("ex4.in","r",stdin); scanf("%d",&n); scanf("%s",a+1); for(re int i=1;i<=n;++i){ sum0[i]=sum0[i-1],sum1[i]=sum1[i-1],sum2[i]=sum2[i-1]; if(a[i]=='0') ++sum0[i]; if(a[i]=='1') ++sum1[i]; if(a[i]=='2') ++sum2[i]; tr[0].add(2*sum0[i-1]-i+n+2); ans+=tr[0].query(2*sum0[i]-i+n); tr[1].add(2*sum1[i-1]-i+n+2); ans+=tr[1].query(2*sum1[i]-i+n); tr[2].add(2*sum2[i-1]-i+n+2); ans+=tr[2].query(2*sum2[i]-i+n); } printf("%lld ",(1ll*n*(n+1)/2)-ans); return 0; }
%%正解大佬gby
#include <iostream> #include <cstring> #include <cstdio> #define lowbit(x) ((x)&(-(x))) #define N 5555555 #define LL long long #define pre(i,j) pre[(i)+nn][j] #define tb(i,j) tb[(i)+nn][j] using namespace std; int nn,pre[2*N][3],tb[2*N][3]; char arr[N]; int dat[N][3]; LL ans; int main(){ scanf("%d",&nn); scanf("%s",arr+1); for(int i=1;i<=nn;i++){ dat[i][0]=dat[i-1][0]+1; dat[i][1]=dat[i-1][1]+1; dat[i][2]=dat[i-1][2]+1; dat[i][arr[i]-'0']-=2; } /*for(int i=0;i<=2;i++){ printf("%d:",i); for(int j=1;j<=nn;j++) cout<<dat[j][i]<<" "; cout<<endl; }*/ ans=(long long)nn*(nn+1)/2; //cout<<ans<<endl; pre(0,0)++,pre(0,1)++,pre(0,2)++; tb(0,0)++ ,tb(0,1)++, tb(0,2)++; static int lst[3]; for(int i=1;i<=nn;i++){ for(int k=0;k<=2;k++){ tb(dat[i][k],k)++; if(dat[i][k]==lst[k]+1){ pre(dat[i][k],k)=pre(lst[k],k)+tb(dat[i][k],k); } else {//dat[i][k]==lst[k]-1 pre(dat[i][k],k)=pre(dat[i][k]-1,k)+tb(dat[i][k],k); pre(lst[k],k)=pre(dat[i][k],k)+tb(lst[k],k); } ans-=i+1-pre(dat[i][k],k); // cout<<k<<":"<<i+1-pre(dat[i][k],k)<<endl; } lst[0]=dat[i][0]; lst[1]=dat[i][1]; lst[2]=dat[i][2]; /*for(int i=0;i<=2;i++){ printf("%d:",i); for(int j=-nn;j<=nn;j++) cout<<pre(j,i)<<" "; cout<<endl; }*/ } cout<<ans<<endl; }
T3:
wqs二分
首先一个暴力dp:
#include<iostream> #include<cstdio> #include<cstring> #define re register using namespace std; const int MAXN=100005; int n,a,b; double p[MAXN],q[MAXN],ans=0.0,f[2][605][605]; inline double max(re double a,re double b){ return a>b?a:b; } signed main(){ while(~scanf("%d%d%d",&n,&a,&b)){ //memset(f,0,sizeof(f)); for(re int i=1;i<=n;++i) scanf("%lf",&p[i]); for(re int i=1;i<=n;++i) scanf("%lf",&q[i]); ans=0.0; //f[0][0][0]=0; memset(f[0],0,sizeof(f[0])); for(re int i=1;i<=n;++i){ for(re int j=0;j<=min(a,n);++j){ for(re int k=0;k<=min(b,n);++k){ f[i&1][j][k]=f[i&1^1][j][k]; if(j!=0) f[i&1][j][k]=max(f[i&1][j][k],f[i&1^1][j-1][k]+p[i]); if(k!=0) f[i&1][j][k]=max(f[i&1][j][k],f[i&1^1][j][k-1]+q[i]); if(j!=0&&k!=0) f[i&1][j][k]=max(f[i&1][j][k],f[i&1^1][j-1][k-1]+p[i]+q[i]-p[i]*q[i]); } } } printf("%0.3lf ",f[n&1][a][b]); } return 0; }
然后优化:
#include<iostream> #include<cstdio> #include<cstring> #define re register #define eps 1e-8 using namespace std; const int MAXN=100005; int n,a,b; double p[MAXN],q[MAXN],ans=0.0,l,r,L,R,f[MAXN],fa[MAXN],fb[MAXN]; inline double max(re double a,re double b){ return a>b?a:b; } bool judge(double na,double nb){ memset(f,0,sizeof(f)); memset(fa,0,sizeof(fa)); memset(fb,0,sizeof(fb)); for(int i=1;i<=n;i++){ f[i]=f[i-1],fa[i]=fa[i-1],fb[i]=fb[i-1]; if(f[i-1]+p[i]>f[i]+na) f[i]=f[i-1]+p[i]-na,fa[i]=fa[i-1]+1,fb[i]=fb[i-1]; if(f[i-1]+q[i]>f[i]+nb) f[i]=f[i-1]+q[i]-nb,fb[i]=fb[i-1]+1,fa[i]=fa[i-1]; if(f[i-1]+p[i]+q[i]-p[i]*q[i]>f[i]+na+nb) f[i]=f[i-1]+p[i]+q[i]-p[i]*q[i]-na-nb,fa[i]=fa[i-1]+1,fb[i]=fb[i-1]+1; } return fb[n]>b; } bool check(double na){ L=0.0,R=1.0; while(R-L>eps){ double mid=(L+R)/2.0; if(judge(na,mid)) L=mid; else R=mid; } judge(na,R); return fa[n]>a; } signed main(){ while(~scanf("%d%d%d",&n,&a,&b)){ for(re int i=1;i<=n;++i) scanf("%lf",&p[i]); for(re int i=1;i<=n;++i) scanf("%lf",&q[i]); l=0.0,r=1.0; ans=0.0; memset(f,0,sizeof(f)); memset(fa,0,sizeof(fa)); memset(fb,0,sizeof(fb)); while(r-l>eps){ double mid=(l+r)/2.0; if(check(mid)) l=mid; else r=mid; } judge(r,R); printf("%0.5lf ",f[n]+a*r+b*R); } return 0; }