省选测试42
总结
这次是真的掉没了,(T1) 加了一个剪枝直接把 (60) 分减没了,以后遇到这种情况还是要稳一点,不要把暴力留着,尤其是这种数据不是很好构造的题。
A. 小B的棋盘
分析
将所有的点按照横坐标从小到大排序,如果横坐标相同按照纵坐标从小到大排序。
如果我们确定了一个对称中心,那么判断方法就是维护两个指针,一个从前向后扫,一个从后向前扫,求出有多少对点匹配,也就可以求出我们需要加入多少点。
因为我们最多只能加入 (k) 个点,所以失配的次数不能超过 (k) 次。
因此就可以把最开始的 (k+1) 个点和最后的 (k+1) 个点选择一对强制匹配,最终的合法方案一定是在这些方案中的。
判断的时候可以 (nlogn) 判断,总的复杂度就是 (k^2nlogn)。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<set>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1e5+5;
int n,k,x[maxn],y[maxn],ans,tp;
struct Node{
long long x,y;
Node(){}
Node(rg long long aa,rg long long bb){
x=aa,y=bb;
}
friend bool operator <(const Node& A,const Node& B){
if(A.x==B.x) return A.y<B.y;
return A.x<B.x;
}
}sta[maxn];
std::set<Node> s,mp,orz;
#define sit std::set<Node>::iterator
bool jud(rg long long nx,rg long long ny){
rg sit it=mp.find(Node(nx,ny));
if(it!=mp.end() && it->x==nx && it->y==ny) return 0;
rg int cnt=0;
rg long long mx,my;
for(rg int i=1;i<=n;i++){
mx=2LL*nx-x[i];
my=2LL*ny-y[i];
it=s.find(Node(mx,my));
if(it==s.end() || it->x!=mx || it->y!=my) cnt++;
if(cnt>k) return 0;
}
mp.insert(Node(nx,ny));
return 1;
}
int main(){
read(n),read(k);
for(rg int i=1;i<=n;i++){
read(x[i]),read(y[i]);
x[i]*=2,y[i]*=2;
s.insert(Node(x[i],y[i]));
sta[++tp]=Node(x[i],y[i]);
}
if(k>=n){
printf("-1
");
return 0;
}
std::sort(sta+1,sta+tp+1);
for(rg int i=1;i<=k+1;i++){
for(rg int j=tp-k;j<=tp;j++){
ans+=jud(1LL*(sta[i].x+sta[j].x)/2LL,1LL*(sta[i].y+sta[j].y)/2LL);
}
}
printf("%d
",ans);
return 0;
}
B. 小B的夏令营
分析
设 (f[t][l][r]) 为当前考虑到了第 (t) 行,前 (i) 行都联通并且剩下的区间是 ([l,r]) 的概率。
暴力的转移是 (n^5) 的,拿前缀和优化一下就是 (n^3) 的。
发现其实并不需要维护具体的 (f) 值,只需要维护前缀和的值就行了,拆一下式子就可以做到 (n^2)。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1505,mod=1e9+7,maxm=1e5+5;
inline int addmod(rg int now1,rg int now2){
return now1+=now2,now1>=mod?now1-mod:now1;
}
inline int delmod(rg int now1,rg int now2){
return now1-=now2,now1<0?now1+mod:now1;
}
inline int mulmod(rg long long now1,rg int now2){
return now1*=now2,now1>=mod?now1%mod:now1;
}
inline int ksm(rg int ds,rg int zs){
rg int nans=1;
while(zs){
if(zs&1) nans=mulmod(nans,ds);
ds=mulmod(ds,ds);
zs>>=1;
}
return nans;
}
int n,m,a,b,k,ans,p[maxn],ny[maxm],jc[maxm],jcc[maxm],gl;
int suml[2][maxn],sumr[2][maxn],suml2[maxn],sumr2[maxn],suml3[maxn],sumr3[maxn],sumpl[maxn],sumpr[maxn];
int getp(rg int l,rg int r){
return mulmod(p[l-1],p[m-r]);
}
int getC(rg int nn,rg int mm){
return mulmod(jc[nn],mulmod(jcc[nn-mm],jcc[mm]));
}
int main(){
read(n),read(m),read(a),read(b),read(k);
gl=mulmod(a,ksm(b,mod-2));
ny[1]=1;
for(rg int i=2;i<maxm;i++) ny[i]=mulmod(mod-mod/i,ny[mod%i]);
jc[0]=jcc[0]=1;
for(rg int i=1;i<maxm;i++) jc[i]=mulmod(jc[i-1],i),jcc[i]=mulmod(jcc[i-1],ny[i]);
for(rg int i=0;i<=m && i<=k;i++) p[i]=mulmod(getC(k,i),mulmod(ksm(gl,i),ksm(delmod(1,gl),k-i)));
for(rg int i=1;i<=m;i++){
for(rg int j=1;j<=i;j++){
sumpr[i]=addmod(sumpr[i],getp(j,i));
}
}
for(rg int i=1;i<=m;i++){
for(rg int j=i;j<=m;j++){
sumpl[i]=addmod(sumpl[i],getp(i,j));
}
}
rg int now=0;
sumr[now][m]=1,suml[now][1]=1;
for(rg int o=1;o<=n;o++){
memset(suml2,0,sizeof(suml2));
memset(sumr2,0,sizeof(sumr2));
memset(suml3,0,sizeof(suml3));
memset(sumr3,0,sizeof(sumr3));
for(rg int i=1;i<=m;i++) sumr2[i]=addmod(sumr2[i-1],sumr[now][i]);
for(rg int i=m;i>=1;i--) suml2[i]=addmod(suml2[i+1],suml[now][i]);
for(rg int i=1;i<=m;i++) sumr3[i]=addmod(sumr3[i-1],mulmod(p[i-1],sumr2[i-1]));
for(rg int i=m;i>=1;i--) suml3[i]=addmod(suml3[i+1],mulmod(p[m-i],suml2[i+1]));
now^=1;
memset(suml[now],0,sizeof(suml[now]));
memset(sumr[now],0,sizeof(sumr[now]));
for(rg int i=1;i<=m;i++){
sumr[now][i]=addmod(sumr[now][i],mulmod(sumr2[m],sumpr[i]));
sumr[now][i]=delmod(sumr[now][i],mulmod(suml2[i+1],sumpr[i]));
sumr[now][i]=delmod(sumr[now][i],mulmod(p[m-i],sumr3[i]));
}
for(rg int i=1;i<=m;i++){
suml[now][i]=addmod(suml[now][i],mulmod(sumr2[m],sumpl[i]));
suml[now][i]=delmod(suml[now][i],mulmod(sumr2[i-1],sumpl[i]));
suml[now][i]=delmod(suml[now][i],mulmod(p[i-1],suml3[i]));
}
}
for(rg int i=1;i<=m;i++) ans=addmod(ans,sumr[now][i]);
printf("%d
",ans);
return 0;
}
C. 小B的图
分析
首先,不管什么 (x),选出的边一定要么是 (A) 的最小生成树边,要么是 (B) 的最小生成树边。
我们搞出 (A) 的最小生成树,把 (B) 的边从小到大依次加入替代 (A) 边。
每条边替换时我们能知道这条边在 $ ge x_0$ 时才会被替换。
排个序然后每次询问二分就行。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#define rg register
template<typename T>void read(rg T& x){
x=0;rg int fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
x*=fh;
}
const int maxn=1e6+5;
struct LCT{
int rev[maxn],wz[maxn],val[maxn],mmax[maxn],ch[maxn][2],fa[maxn],sta[maxn],tp;
void push_up(rg int da){
rg int lc=ch[da][0],rc=ch[da][1];
mmax[da]=std::max(val[da],std::max(mmax[lc],mmax[rc]));
if(mmax[da]==val[da]) wz[da]=da;
else if(mmax[da]==mmax[lc]) wz[da]=wz[lc];
else wz[da]=wz[rc];
}
void push_down(rg int da){
if(!rev[da]) return;
rg int lc=ch[da][0],rc=ch[da][1];
rev[da]^=1,rev[lc]^=1,rev[rc]^=1;
std::swap(ch[da][0],ch[da][1]);
}
bool isroot(rg int da){
return (ch[fa[da]][0]!=da)&&(ch[fa[da]][1]!=da);
}
void xuanzh(rg int x){
rg int y=fa[x];
rg int z=fa[y];
rg int k=(ch[y][1]==x);
if(!isroot(y)) ch[z][ch[z][1]==y]=x;
fa[x]=z;
ch[y][k]=ch[x][k^1];
fa[ch[x][k^1]]=y;
ch[x][k^1]=y;
fa[y]=x;
push_up(y);
push_up(x);
}
void splay(rg int x){
sta[tp=1]=x;
for(rg int i=x;!isroot(i);i=fa[i]) sta[++tp]=fa[i];
for(rg int i=tp;i>=1;i--) push_down(sta[i]);
while(!isroot(x)){
rg int y=fa[x];
rg int z=fa[y];
if(!isroot(y)){
(ch[z][1]==y)^(ch[y][1]==x)?xuanzh(x):xuanzh(y);
}
xuanzh(x);
}
}
void access(rg int x){
for(rg int y=0;x;y=x,x=fa[x]){
splay(x);
ch[x][1]=y;
push_up(x);
}
}
void makeroot(rg int x){
access(x);
splay(x);
rev[x]^=1;
push_down(x);
}
void split(rg int x,rg int y){
makeroot(x);
access(y);
splay(y);
}
void link(rg int x,rg int y){
makeroot(x);
fa[x]=y;
}
void cut(rg int x,rg int y){
split(x,y);
ch[y][0]=fa[x]=0;
push_up(y);
}
}lct;
int n,a,b,q,fa[maxn],idx[maxn],idy[maxn],idw[maxn],tp,wz[maxn];
struct jie{
int zb,yb,val;
jie(){}
jie(rg int aa,rg int bb,rg int cc){
zb=aa,yb=bb,val=cc;
}
}c[maxn];
bool cmp(rg jie aa,rg jie bb){
return aa.val<bb.val;
}
void init(){
for(rg int i=1;i<=n;i++) fa[i]=i;
}
int zhao(rg int xx){
if(xx==fa[xx]) return xx;
return fa[xx]=zhao(fa[xx]);
}
long long ans[maxn];
struct asd{
int val,tim;
asd(){}
asd(rg int aa,rg int bb){
val=aa,tim=bb;
}
}sta[maxn];
bool cmp2(rg asd aa,rg asd bb){
return aa.tim<bb.tim;
}
int main(){
read(n),read(a),read(b),read(q);
for(rg int i=0;i<=n;i++) lct.val[i]=lct.mmax[i]=-0x3f3f3f3f;
rg int aa,bb,cc;
for(rg int i=1;i<=a;i++){
read(aa),read(bb),read(cc);
c[i]=jie(aa,bb,cc);
}
std::sort(c+1,c+a+1,cmp);
init();
for(rg int i=1;i<=a;i++){
aa=zhao(c[i].zb),bb=zhao(c[i].yb);
if(aa==bb) continue;
fa[aa]=bb;
lct.val[i+n]=lct.mmax[i+n]=c[i].val;
idx[i+n]=c[i].zb,idy[i+n]=c[i].yb,idw[i+n]=c[i].val;
lct.link(c[i].zb,i+n),lct.link(c[i].yb,i+n);
ans[0]+=c[i].val;
}
for(rg int i=1;i<=b;i++){
read(aa),read(bb),read(cc);
c[i]=jie(aa,bb,cc);
}
std::sort(c+1,c+b+1,cmp);
init();
for(rg int i=1;i<=b;i++){
aa=zhao(c[i].zb),bb=zhao(c[i].yb);
if(aa==bb) continue;
fa[aa]=bb;
lct.split(c[i].zb,c[i].yb);
cc=lct.wz[c[i].yb];
lct.cut(idx[cc],cc),lct.cut(idy[cc],cc);
lct.val[n+a+i]=lct.mmax[n+a+i]=-0x3f3f3f3f;
lct.link(c[i].zb,n+a+i),lct.link(c[i].yb,n+a+i);
sta[++tp]=asd(c[i].val-idw[cc],(int)std::ceil(1.0*(c[i].val-idw[cc])/2.0));
}
std::sort(sta+1,sta+tp+1,cmp2);
for(rg int i=1;i<=tp;i++) ans[i]=ans[i-1]+sta[i].val;
for(rg int i=1;i<=tp;i++) wz[i]=sta[i].tim;
for(rg int i=1;i<=q;i++){
read(aa);
if(aa>=sta[tp].tim){
printf("%lld
",ans[tp]-1LL*(n-1)*aa);
} else {
bb=std::upper_bound(wz+1,wz+tp+1,aa)-wz;
printf("%lld
",ans[bb-1]+1LL*(n-1-(bb-1)-(bb-1))*aa);
}
}
return 0;
}