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
咕?
原文地址:https://www.cnblogs.com/Jackpei/p/11675328.html