码迷,mamicode.com
首页 > 其他好文 > 详细

20191008,10,12

时间:2019-10-15 10:03:08      阅读:49      评论:0      收藏:0      [点我收藏+]

标签:pair   判断   方案   2-2   cond   tar   putchar   背包   scanf   

2019.10.08

T1 20pts

考试时\(n^2\)写挂,最后也不知道\(x\)用来干啥。
70pts: \(\mathcal{O}(n^2)\)
\(f_i\) 表示一行和为 \(i\) 的方案数。显然
\(f_i={m \choose i}x^{m-i}y^i\)
\(g_i\) 表示一行和大于等于 \(i\) 的方案数。
考虑枚举最大值是多少,多少个 \(B\) 是等于这个最大值,那么答案显然为
\(\sum_{i=0}^m\sum_{j=1}^n{n\choose j}f_i^jg_{i+1}^{n-j}i\)
100pts:
想一想,发现最小值为 \(i\) 的方案数为:\(g_i^n-g_{i+1}^n\)

#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=200010,M=1000000007;
int n,m,x,y,fac[N],Inv[N],rfac[N],sum[N],a[100],ans;
inline int C(int n,int m) {
    return 1ll*fac[n]*rfac[m]%M*rfac[n-m]%M;
}
inline int qpow(int a,int b) { R ret=1;
    for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret;
}
inline void main() {
//  freopen("past.in","r",stdin);
//  freopen("past.out","w",stdout);
//  n=g(),m=g(),x=g(),y=g();
//  fac[0]=fac[1]=1; for(R i=2;i<=max(n,m);++i) fac[i]=1ll*fac[i-1]*i%M;
//  Inv[0]=Inv[1]=1; for(R i=2;i<=max(n,m);++i) Inv[i]=M-1ll*M/i*Inv[M%i]%M;
//  rfac[0]=rfac[1]=1; for(R i=2;i<=max(n,m);++i) rfac[i]=1ll*rfac[i-1]*Inv[i]%M;
//  for(R k=m;k>=0;--k) { 
//      R tmp=1ll*C(m,k)*qpow(x,m-k)%M*qpow(y,k)%M,inv=qpow(sum[k+1],M-2); 
//      R t=tmp,I=qpow(sum[k+1],n-1); R ttt=1ll*C(m,k)*qpow(x,m-k)%M*qpow(y,k)%M;
//      for(R i=1;i<=n;++i) {
//          if(n==i) I=1;
//          ans=(ans+1ll*C(n,i)*tmp%M*I%M*k)%M; 
//          tmp=1ll*tmp*t%M,I=1ll*I*inv%M; 
//      } sum[k]=(sum[k+1]+1ll*C(m,k)*qpow(x,m-k)%M*qpow(y,k))%M;
//  } printf("%d\n",ans);
    n=g(),m=g(),x=g(),y=g();
    fac[0]=fac[1]=1; for(R i=2;i<=max(n,m);++i) fac[i]=1ll*fac[i-1]*i%M;
    Inv[0]=Inv[1]=1; for(R i=2;i<=max(n,m);++i) Inv[i]=M-1ll*M/i*Inv[M%i]%M;
    rfac[0]=rfac[1]=1; for(R i=2;i<=max(n,m);++i) rfac[i]=1ll*rfac[i-1]*Inv[i]%M;   
    for(R i=m;~i;--i) sum[i]=(sum[i+1]+1ll*C(m,i)*qpow(x,m-i)%M*qpow(y,i))%M;
    for(R i=1;i<=m;++i) ans=(ans+1ll*(qpow(sum[i],n)-qpow(sum[i+1],n)+M)*i%M)%M;
    printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}

T2 60pts

操作树。。。考试时失了智写的压位。。。于是改题时接着压位。。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#define ll long long
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
}   const int M=100010; const short B=32; const unsigned E=-1,S=31,T=5;
unsigned mem[31255]; int n,m,k,ans[M],sum;
#define P(i,j) ((i-1)*m+j-1)
struct node {int op,h,l;}q[M];
vector <int> e[M];
const unsigned char __popcount_tab[] = {
  0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,
  3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8,
};
 
inline int __builtin_popcount (unsigned x) {
  return __popcount_tab[(x >> 0) & 0xff]  + __popcount_tab[(x >>  8) & 0xff]  + __popcount_tab[(x >> 16) & 0xff] + __popcount_tab[(x >> 24) & 0xff];
}
inline void operation(int whi) {
    register short p1,p2,q1,q2;
    register unsigned ll tmp;
    register int pos1,pos2,pos;
    register int op=q[whi].op,h=q[whi].h,l=q[whi].l;
    if(op==1) {pos=P(h,l); p1=pos>>T,p2=pos&S; ((mem[p1]>>(p2))&1)?--sum:++sum; mem[p1]^=(1u<<p2);} 
    else if(op==2) {
        pos1=P(h,1),pos2=P(h,m),p1=pos1>>T,q1=pos2>>T;
        if(p1==q1) { p2=pos1&S,q2=pos2&S; 
            tmp=((((mem[p1]>>p2)<<p2)<<(B-q2-1)));
            sum+=(pos2-pos1+1-2*__builtin_popcount(tmp));
            tmp=(((E>>p2)<<p2)<<(B-q2-1))>>(B-q2-1); mem[p1]^=tmp;
        } else if(p1+1==q1) { 
            p2=pos1&S,q2=pos2&S;tmp=mem[p1]>>p2; 
            sum+=(B-p2-2*__builtin_popcount(tmp));
            tmp=(E>>p2)<<p2;mem[p1]^=tmp,q2=B-q2-1;tmp=mem[q1]<<q2;
            sum+=(B-q2-2*__builtin_popcount(tmp));
            tmp=(E<<q2)>>q2;mem[q1]^=tmp;
        } else {
            p2=pos1&S,q2=pos2&S;tmp=mem[p1]>>p2;
            sum+=(B-p2-2*__builtin_popcount(tmp));
            tmp=(E>>p2)<<p2;mem[p1]^=tmp;q2=B-q2-1;tmp=mem[q1]<<q2;
            sum+=(B-q2-2*__builtin_popcount(tmp));
            tmp=(E<<q2)>>q2;mem[q1]^=tmp;
            for(R j=p1+1,lim=q1-1;j<=lim;++j) 
                sum+=(B-2*__builtin_popcount(mem[j])),mem[j]^=E;
        } 
    } else if(op==3) {
        pos=P(0,l); for(R j=1;j<=n;++j) { pos+=m; p1=pos>>T,p2=pos&S;
            ((mem[p1]>>p2)&1)?--sum:++sum; mem[p1]^=1u<<p2;
        }
    }
}
inline void dfs(int u) { operation(u); ans[u]=sum; 
    for(R i=0,lim=e[u].size();i<lim;++i) dfs(e[u][i]); operation(u); 
}
inline void main() {
    n=g(),m=g(),k=g(); 
    for(R i=1,op;i<=k;++i) { op=q[i].op=g();
        if(op==1) q[i].h=g(),q[i].l=g(); if(op==2) q[i].h=g();
        if(op==3) q[i].l=g(); if(op==4) q[i].h=g(),e[q[i].h].push_back(i);
        else e[i-1].push_back(i);
    } dfs(0); for(R i=1;i<=k;++i) printf("%d\n",ans[i]);
}
} signed main() {Luitaryi::main(); return 0;}

T3 0pts

由于关键节点很少,考虑状压。
我们发现,如果按顺序从小到大填入数字,必须先填关键点,再填关键点旁边的点。
我们要先预处理与关键点有关的点的点集(同时包括关键点)。
\(f[i][S]\)表示这个点集中填了\(i\)个点,关键点的状态是\(S\)
转移:填一个关键点,或填一个与关键点有关的点。

#include<bits/stdc++.h>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=10010,M=1000000007;
const int dx[]={-1,0,1,-1,0,1,-1,0,1},dy[]={1,1,1,0,0,0,-1,-1,-1};
struct node { int x,y; node() {}
    node(int _x,int _y) {x=_x,y=_y;}
}; vector <node> s; bool flg[150][150],vis[150];
int n,m,k,h[N],lim,fac[N],rfac[N],x[N],y[N],f[150][N];
inline int qpow(int a,int b) { R ret=1;
    for(;b;b>>=1,a=1ll*a*a%M) if(b&1) ret=1ll*ret*a%M; return ret; 
}
inline void main() {
    n=g(),m=g(),k=g(); lim=1<<k;
    //freopen("out.out","w",stdout);
    fac[0]=fac[1]=1; for(R i=2;i<=n*m;++i) fac[i]=1ll*fac[i-1]*i%M;
    rfac[n*m]=qpow(fac[n*m],M-2); rfac[0]=rfac[1]=1;
    for(R i=n*m;i>=3;--i) rfac[i-1]=1ll*rfac[i]*i%M;
    for(R i=0;i<k;++i) x[i]=g(),y[i]=g();
    for(R i=0;i<k;++i) for(R j=0;j<9;++j) {
        R X=x[i]+dx[j],Y=y[i]+dy[j];
        if(X<1||X>n||Y<1||Y>m||flg[X][Y]) continue;
        flg[X][Y]=true,s.push_back(node(X,Y));
    } 
    for(R i=0;i<lim;++i) { 
        memset(vis,0,sizeof vis);
        for(R j=0;j<k;++j) if(!(i>>j&1)) {
            for(R l=0;l<s.size();++l)
                if(!(s[l].x==x[j]&&s[l].y==y[j])&&abs(s[l].x-x[j])<=1&&abs(s[l].y-y[j])<=1) 
                    vis[l]=1; 
        } for(R j=0;j<s.size();++j) if(vis[j]) ++h[i];
    } f[0][0]=1;
    for(R i=0;i<s.size();++i) {
        for(R j=0;j<lim;++j) { R num=0;
            for(R l=0;l<k;++l) if(!(j>>l&1)) 
                (f[i+1][j^(1<<l)]+=f[i][j])%=M,++num;
            if(s.size()-i-h[j]-num>0) f[i+1][j]=(f[i+1][j]+1ll*(s.size()-i-h[j]-num)*f[i][j])%M;//判断能否填与关键点有关的点
        }
    } printf("%d\n",1ll*f[s.size()][lim-1]*fac[n*m]%M*rfac[s.size()]%M);
}
} signed main() {Luitaryi::main(); return 0;}

2019.10.10

T1 100pts

没话。
%最小生成树的那个神仙

#include<bits/stdc++.h>
#define R register int 
#define ll long long
using namespace std;
namespace Luitaryi { 
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=1010,M=1000010;
int n,m,tx,ty,cnt; char s[N];
int vr[M<<2],nxt[M<<2],fir[M],w[M<<2],d[M];
bool vis[M],a[N][N];
inline void add(int u,int v,int ww) {
    vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt,w[cnt]=ww;
    vr[++cnt]=u,nxt[cnt]=fir[v],fir[v]=cnt,w[cnt]=ww;
}
#define P(i,j) ((i-1)*m+j)
priority_queue<pair<int,int> > q;
inline void dijk() {
    memset(d,0x3f,sizeof d); d[P(n,1)]=0;
    q.push(make_pair(0,P(n,1)));
    while(q.size()) { R u=q.top().second; q.pop(); 
        if(vis[u]) continue; vis[u]=1;
        for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
            if(d[v]>max(d[u],w[i])) {
                d[v]=max(d[u],w[i]); 
                q.push(make_pair(-d[v],v));
            }
        }
    }
}
inline void main() {
    n=g(),m=g(); for(R i=1;i<=n;++i) {
        scanf("%s",s+1); for(R j=1;j<=m;++j) a[i][j]=(s[j]=='#');
    } tx=g(),ty=g(); 
    for(R i=1;i<=n;++i) for(R j=1;j<=m;++j) if(a[i][j]) { R p=1;
        while(i-p>0&&!a[i-p][j]) ++p;
        if(i-p>0) add(P(i,j),P(i-p,j),p);
        if(a[i][j-1]) add(P(i,j),P(i,j-1),0);
        //if(a[i][j+1]) add(P(i,j),P(i,j+1),0);
    } dijk(); printf("%d\n",d[P(tx,ty)]);
}
} signed main() {Luitaryi::main(); return 0;}

T2

我们假设刚开始所有数都在集合 \(A\),而集合 \(B\) 是空的。
所以我们有 \(R_A-L_B>R_B-L_A\) (显然吧)
然后我们可以把 \(A\) 中的一些东西转到 \(B\) 中,设所有转移的两个端点和分别为\(l,r\)
\(R_A-r-(L_B+l)>(R_B+r)-(L_A-l)\)
\(R_A-R_B+L_A-L_B>2*(l+r)\)
于是背包。
奉上最短的代码:

#include<bits/stdc++.h>
using namespace std;int l,r,R,s;bitset<40001>f=1;main(){for(cin>>l;cin>>l>>r;)R+=r,s+=l+=r,f|=f<<l;for(s/=2;!f[s];--s);cout<<R-s;}

T3 0pts

考场上把 change 和 query 写到一起,成功保龄
我们发现模数很奇怪,于是打打表,发现平方一会就不变了。。。于是和区间开根基本一样了。

#include<bits/stdc++.h>
#define R register int 
#define ll unsigned long long
using namespace std;
namespace Luitaryi { 
inline ll g() { register ll x=0;
    register char ch; while(!isdigit(ch=getchar()));
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x;
} 
inline int gi() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x;
} const int N=65540; const ll M=2305843008676823040ull;
int n,m; ll sum[N<<2]; bool flg[N<<2];
#define ls (tr<<1)
#define rs (tr<<1|1)
inline void mod(ll& a,ll b) {a+=b; if(a>=M) a-=M;}
inline ll mode(ll a,ll b) {a+=b; if(a>=M) a-=M; return a;}
inline ll mul(ll a,ll b) {
    register unsigned __int128 t=a;
    t=t*b%M; return t;
}
inline void build(int tr,int l,int r) {
    if(l==r) {sum[tr]=g(); return ;} R md=l+r>>1;   
    build(ls,l,md),build(rs,md+1,r); sum[tr]=(sum[ls]+sum[rs])%M;
}
inline void change(int tr,int l,int r,int LL,int RR) {
    if(l==r) { register ll tmp=sum[tr]; 
        sum[tr]=mul(sum[tr],sum[tr]); 
        flg[tr]=(sum[tr]==tmp); return ;
    } R md=l+r>>1;
    if(LL<=md&&!flg[ls]) change(ls,l,md,LL,RR);
    if(RR>md&&!flg[rs]) change(rs,md+1,r,LL,RR);
    sum[tr]=mode(sum[ls],sum[rs]); flg[tr]=flg[ls]&&flg[rs];
}
inline ll query(int tr,int l,int r,int LL,int RR) {
    if(LL<=l&&r<=RR) return sum[tr]; R md=l+r>>1; register ll ret=0;
    if(LL<=md) ret=query(ls,l,md,LL,RR);
    if(RR>md) mod(ret,query(rs,md+1,r,LL,RR)); return ret;
}
inline void main() {
    n=gi(),m=gi(); build(1,1,n);
    for(R i=1,l,r;i<=m;++i) 
        l=gi(),r=gi(),printf("%llu\n",query(1,1,n,l,r)),change(1,1,n,l,r);
}
} signed main() {Luitaryi::main(); return 0;}

2019.10.12

T1 90pts

大模拟。。。有一个点写错了,竟然还有分(万幸)

#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
}
inline int g(char* s) { R x=0,f=1;
    register char ch; while(!isdigit(ch=*s++)) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=*s++)); return x*f;
} const int N=10;
char s[5]; int a[N],b[N],anss[N],c[N<<1],ans=8,tp;
inline void main() {
    for(R i=1;i<=7;++i) {
        scanf("%s",s); if(isalpha(s[0])) {
            if(s[0]=='A') a[i]=14; if(s[0]=='J') a[i]=11;
            if(s[0]=='Q') a[i]=12; if(s[0]=='K') a[i]=13;
        } else a[i]=g(s);
    } swap(a[1],a[6]),swap(a[2],a[7]);
    for(R i=1;i<=7;++i) for(R j=i+1;j<=7;++j) 
    for(R k=j+1;k<=7;++k) for(R l=k+1;l<=7;++l) 
    for(R m=l+1;m<=7;++m) {
        memset(c,0,sizeof c),tp=7;
        b[1]=a[l],b[2]=a[m],b[3]=a[i],b[4]=a[j],b[5]=a[k];
        sort(b+1,b+6,greater<int>()); for(R t=1;t<=5;++t) {
            ++c[b[t]]; if(c[b[t]]==4) tp=1;
            else if(c[b[t]]==3) {
                if(tp==5) tp=2; else tp=4;
            } else if(c[b[t]]==2) {
                if(tp==6) tp=5; else if(tp==4) tp=2; else tp=6;
            }
        } register bool fg=true;
        if(tp==7) {for(R t=2;t<=5;++t) fg&=(b[t-1]-b[t]==1); if(fg) tp=3;
            else if(b[1]==14) { R p=1; fg=true;
                while(b[p]==14) b[p]=1,++p;
                sort(b+1,b+6,greater<int>());
                for(R t=2;t<=5;++t) fg&=(b[t-1]-b[t]==1);
                if(fg) tp=3;
                p=5; while(b[p]==1) b[p]=14,--p;
                if(!fg) sort(b+1,b+6,greater<int>());
            }   
        }           
        if(tp<ans) ans=tp,memcpy(anss,b,sizeof anss);
        else if(tp==ans) {
            for(R t=1;t<=5;++t) {
                if(b[t]>anss[t]) {
                    memcpy(anss,b,sizeof anss); break;
                } if(b[t]<anss[t]) break;
            }
        }
    }
    for(R i=1;i<=5;++i) {
        if(anss[i]>10) {
            if(anss[i]==11) putchar('J'); if(anss[i]==12) putchar('Q');
            if(anss[i]==13) putchar('K'); if(anss[i]==14) putchar('A');
            putchar(' ');
        } else printf("%d ",anss[i]);
    }
}
} signed main() {Luitaryi::main(); return 0;}

T2 50pts

竟然写的二分差值。。。但是0怎么办?(又是万幸没卡死我)
于是我们发现,当我们取的数越接近这段的平均数,越优。
又因为序列是不减的,所以平均数也是不减的,所以平均数的位置也是不减的。
%那个写斜率优化的神仙

#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
    do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*f;
} const int N=100010;
int n,k,a[N],t=1;
ll p[N],ps[N],ans=4e18;
inline void main() {
    n=g(),k=g(); for(R i=1;i<=n;++i) a[i]=g();
    for(R i=1;i<=n;++i) p[i]=p[i-1]+a[i];
    for(R i=1;i<=n;++i) ps[i]=ps[i-1]+1ll*a[i]*a[i];
    for(R i=k,LL,RR;i<=n;++i) { LL=i-k,RR=i;
        while(1ll*k*a[t]*a[t]-2*a[t]*(p[RR]-p[LL])+ps[RR]-ps[LL]>=
                    1ll*k*a[t+1]*a[t+1]-2*a[t+1]*(p[RR]-p[LL])+ps[RR]-ps[LL]&&t<RR) ++t;
        ans=min(ans,1ll*k*a[t]*a[t]-2*a[t]*(p[RR]-p[LL])+ps[RR]-ps[LL]);
    } printf("%lld\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}

T3

咕?

20191008,10,12

标签:pair   判断   方案   2-2   cond   tar   putchar   背包   scanf   

原文地址:https://www.cnblogs.com/Jackpei/p/11675328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!