20191008,10,12

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}^msum_{j=1}^n{nchoose 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
",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
",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
",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
",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
",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
",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
",ans);
}
} signed main() {Luitaryi::main(); return 0;}

T3

咕?

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