CodeChef November Challenge 2019 Division 1题解
AFO前的最后一场CC了……好好打吧……
\(SIMGAM\)
偶数行的必定两人平分,所以只要抢奇数行中间那个就行了
这题怎么被爆破了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
const int N=10005;
int a[N],c[15],n,m,T,tot;ll res;
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),tot=0,res=0;
fp(i,1,n){
scanf("%d",&m);
fp(j,1,m)scanf("%d",&c[j]);
fp(j,1,m>>1)res+=c[j];
if(m&1)a[++tot]=c[(m+1)>>1];
}
sort(a+1,a+1+tot);
for(R int i=tot;i>0;i-=2)res+=a[i];
printf("%lld\n",res);
}
return 0;
}
\(PHCUL\)
\(O(n^2)\)随便跑一跑就是了
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const double inf=1e12;
const int N=5005;
typedef long long ll;
struct node{
int x,y;
inline node(){}
inline node(R int xx,R int yy):x(xx),y(yy){}
inline node operator -(const node &b)const{return node(x-b.x,y-b.y);}
inline double norm(){return sqrt(1ll*x*x+1ll*y*y);}
}p[N],q[N],o[N],ljz;
double mnp[N],mnq[N],mnpo[N],mnqo[N],res;
int n,m,k,T;
int main(){
// freopen("testdata.in","r",stdin);
for(scanf("%d",&T);T;--T){
scanf("%d%d",&ljz.x,&ljz.y);
scanf("%d%d%d",&n,&m,&k);
fp(i,1,n){
scanf("%d%d",&p[i].x,&p[i].y);
mnp[i]=mnpo[i]=inf;
}
fp(i,1,m){
scanf("%d%d",&q[i].x,&q[i].y);
mnq[i]=mnqo[i]=inf;
}
fp(i,1,k)scanf("%d%d",&o[i].x,&o[i].y);
fp(i,1,n)fp(j,1,k)cmin(mnpo[i],(p[i]-o[j]).norm());
fp(i,1,m)fp(j,1,k)cmin(mnqo[i],(q[i]-o[j]).norm());
fp(i,1,n)fp(j,1,m){
cmin(mnp[i],mnqo[j]+(p[i]-q[j]).norm());
cmin(mnq[j],mnpo[i]+(p[i]-q[j]).norm());
}
res=inf;
fp(i,1,n)cmin(res,mnp[i]+(p[i]-ljz).norm());
fp(i,1,m)cmin(res,mnq[i]+(q[i]-ljz).norm());
printf("%.15lf\n",res);
}
return 0;
}
\(WEIRDO\)
一个串属于\(A\),当且仅当对于任意辅音\(s[i]\),\(s[i-1],s[i-2],s[i+1],s[i+2]\)(如果存在的话)都是元音,直接暴力就行
由于精度会炸,需要取对数
由于\(n\leq 10\)的时候取对数精度会炸,所以这个时候直接暴力
//quming
#include<bits/stdc++.h>
#define R register
#define double long double
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=2e5+5;
char s[N];int cnt[2][26],cc[2][26],vis[26],val[233],cp[2],T,L,n;double res,ret;
inline int ID(){
fp(i,1,n)if(!val[s[i]]){
if(i>1&&!val[s[i-1]])return 1;
if(i>2&&!val[s[i-2]])return 1;
}
return 0;
}
void calc(int id){
++cp[id];
fp(i,0,25)vis[i]=0;
fp(i,1,n)++cnt[id][s[i]-'a'],vis[s[i]-'a']=1;
fp(i,0,25)cc[id][i]+=vis[i];
}
void get(){
res=1;
fp(i,0,25){
if(cc[0][i])res*=cc[0][i];
if(cc[1][i])res/=cc[1][i];
}
if(n<=10){
fp(i,0,25){
if(cnt[1][i]>1)res*=pow(cnt[1][i],cp[1]);
if(cnt[0][i]>1)res/=pow(cnt[0][i],cp[0]);
}
if(res>=1e7)return puts("Infinity"),void();
printf("%.15Lf\n",res);
return;
}
ret=0;
fp(i,0,25){
if(cnt[1][i])ret+=cp[1]*log(cnt[1][i]);
if(cnt[0][i])ret-=cp[0]*log(cnt[0][i]);
}
if(ret>=17)return puts("Infinity"),void();
res*=exp(ret);
if(res>=1e7)return puts("Infinity"),void();
printf("%.15Lf\n",res);
}
int main(){
// freopen("testdata.in","r",stdin);
val['a']=val['e']=val['i']=val['o']=val['u']=1;
for(scanf("%d",&T);T;--T){
scanf("%d",&L);
memset(cnt,0,sizeof(cnt));
memset(cc,0,sizeof(cc));
memset(cp,0,sizeof(cp));
fp(i,1,L){
scanf("%s",s+1),n=strlen(s+1);
calc(ID());
}
get();
}
return 0;
}
\(LSTBTF\)
辛辛苦苦想半天,一发暴力交上去就\(A\)了……
似乎是因为最终答案中前缀\(1\)的个数很多,所以实际枚举的状态非常少……
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
int a[15],n,T,fl;
void dfs(int d,int c,int res){
if(!c){
R int t=sqrt(res);
if(t*t==res)fl=1;
return;
}
if(d==9){
a[d]=c;
dfs(d+1,0,res+81*c);
if(!fl)a[d]=0;
return;
}
fd(i,c,0){
a[d]=i;
dfs(d+1,c-i,res+d*d*i);
if(fl)return;
a[d]=0;
}
}
int main(){
for(scanf("%d",&T);T;--T){
scanf("%d",&n),fl=0;
memset(a,0,sizeof(a));
dfs(1,n,0);
if(!fl)puts("-1");
else{
fp(i,1,9)fp(j,1,a[i])putchar(i+'0');
putchar('\n');
}
}
return 0;
}
\(FAILURE\)
按类似\(tarjan\)求割点的办法求出删掉每个点之后会增加的连通块个数,那么对于每个点判断删掉它之后图中边数+连通块数=点数是否成立就是了
多组数据记得清空
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int N=1e5+5;
struct eg{int v,nx;}e[N<<1];int head[N],tot;
inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
int dfn[N],low[N],np[N],deg[N],n,m,T,tim,sz,id;
inline void clr(){
memset(head,0,(n+1)<<2);
memset(dfn,0,(n+1)<<2);
memset(deg,0,(n+1)<<2);
tot=tim=0;
}
void tarjan(int u){
dfn[u]=low[u]=++tim;
np[u]=0;
go(u)if(dfn[v])cmin(low[u],dfn[v]);
else{
tarjan(v),cmin(low[u],low[v]);
np[u]+=(low[v]>=dfn[u]);
}
}
int main(){
// freopen("testdata.in","r",stdin);
for(scanf("%d",&T);T;--T){
scanf("%d%d",&n,&m);
for(R int i=1,u,v;i<=m;++i){
scanf("%d%d",&u,&v),add(u,v),add(v,u);
++deg[u],++deg[v];
}
sz=0;
fp(i,1,n)if(!dfn[i])tarjan(i),--np[i],++sz;
id=-1;
if(m+sz!=n)fp(i,1,n)if(m-deg[i]+sz+np[i]==n-1){id=i;break;}
printf("%d\n",id);
clr();
}
return 0;
}
\(MDSWIN\)
对每一堆考虑因子个数就是个\(Nim\)了
\(K-Nim\),在\(Nim\)的基础上变为每次最多可以取\(K\)堆石子进行操作,每堆取的数量可以不同
结论:记\(c_i\)为二进制第\(i\)位为\(1\)的数的个数,后手必胜当且仅当对于每一个\(i\)都有\(c_i\equiv 0\pmod{K+1}\)
证明留待读者自行思考,因为我也不会
那么我们把每个数二进制上每一位的\(1\)变成对应三进制每一位上的\(1\),做个三维\(FWT\)就行了
不会三维FWT的请自行百度
//quming
#include<bits/stdc++.h>
#define R register
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
const int P=1e9+7;
inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
inline int inc(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
struct cp{
int x,y;
inline cp(){}
inline cp(R int xx,R int yy):x(xx),y(yy){}
inline cp operator +(const cp &b)const{return cp(inc(x,b.x),inc(y,b.y));}
inline cp operator -(const cp &b)const{return cp(inc(x,P-b.x),inc(y,P-b.y));}
inline cp operator *(const cp &b)const{
return cp(inc(mul(x,b.x),P-mul(y,b.y)),(0ll+mul(x,b.y)+mul(y,b.x)+P-mul(y,b.y))%P);
}
}f[200005];
inline cp ksm(R cp x,R int y){
R cp res(1,0);
for(;y;y>>=1,x=x*x)if(y&1)res=res*x;
return res;
}
inline cp calc1(R cp b){return cp(inc(0,P-b.y),inc(b.x,P-b.y));}
inline cp calc2(R cp b){return cp(inc(b.y,P-b.x),inc(0,P-b.x));}
int lim,inv;
void DFT(cp *A){
for(R int mid=1;mid<lim;mid*=3)
for(R int j=0;j<lim;j+=mid*3)
fp(k,0,mid-1){
cp x=A[j+k],y=A[j+k+mid],z=A[j+k+(mid<<1)];
A[j+k]=x+y+z,
A[j+k+mid]=x+calc1(y)+calc2(z),
A[j+k+(mid<<1)]=x+calc2(y)+calc1(z);
}
}
void IDFT(cp *A){
for(R int mid=1;mid<lim;mid*=3)
for(R int j=0;j<lim;j+=mid*3)
fp(k,0,mid-1){
cp x=A[j+k],y=A[j+k+mid],z=A[j+k+(mid<<1)];
A[j+k]=x+y+z,
A[j+k+mid]=x+calc2(y)+calc1(z),
A[j+k+(mid<<1)]=x+calc1(y)+calc2(z);
}
fp(i,0,lim-1)A[i].x=mul(A[i].x,inv);
}
const int N=1e6+5;
bitset<N>vis;int p[N],m;
void init(int n=40000){
fp(i,2,n){
if(!vis[i])p[++m]=i;
for(R int j=1;j<=m&&i*p[j]<=n;++j){
vis[i*p[j]]=1;
if(i%p[j]==0)break;
}
}
}
inline void did(R int x){
R int ljz=1,c,pw,res;
for(R int i=1;i<=m&&1ll*p[i]*p[i]<=x;++i)
if(x%p[i]==0){
c=0;while(x%p[i]==0)++c,x/=p[i];
ljz*=c+1;
}
if(x!=1)ljz*=2;
--ljz,pw=1,res=0;
for(;ljz;ljz>>=1,pw*=3)if(ljz&1)res+=pw;
++f[res].x;
}
int T,n,k,x;
int main(){
// freopen("testdata.in","r",stdin);
init();
lim=177147,inv=ksm(lim,P-2);
for(scanf("%d",&T);T;--T){
scanf("%d%d",&n,&k);
memset(f,0,sizeof(f));
fp(i,1,n)scanf("%d",&x),did(x);
DFT(f);
fp(i,0,lim-1)f[i]=ksm(f[i],k);
IDFT(f);
printf("%d\n",inc(ksm(n,k),P-f[0].x));
}
return 0;
}
\(PBOXES\)
好像并不是很难啊,我打月赛的时候可能在睡觉吧
耀华哥哥好厉害
首先以\(s\)为第一关键字\(p\)为第二关键字\(sort\),那么选的二元组\((i,j)\)的贡献肯定是\(p_j-p_i\),其中\(j>i\),那么可以直接把费用流的图建出来,其中方便起见把\(1\)到\(n\)建成一条从左连到右的链
然后发现增广路有两种情况,一种是正着增广,即前面所说的\(p_j-p_i\),这个没有条件,另一种是倒着增广,要求选的这一段流量至少为\(1\)
然后发现第一种增广路会使区间的流量增加\(1\),第二种会使区间的流量减少\(1\),那么用线段树维护就行了
问题是一条边的流量可能不停地在\(0/1\)之间切换,不过我们发现边的流量最小为\(0\),那么一条边的流量为\(0\)时他肯定是区间最小值
所以我们线段树上每个节点维护\(r1,r2\),其中\(r1\)表示经过一条流量为区间最小值的边时的最优答案,不经过流量为区间最小值的边时的最优答案(注意这里最优答案两种都可以),那么最终的答案就是\(r2\),而\(r1\)可以更新答案当且仅当区间流量最小值不为\(0\)。要维护这两个东西只要分别维护\(pmn,smx\)分别表示区间中左端连续的不经过区间最小值的部分和右端连续的不经过区间最小值的部分即可
具体细节建议看代码理解
//quming
#include<bits/stdc++.h>
#define R register
#define fi first
#define se second
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
const int N=2e5+5,inf=1e9+7;
struct loli{
int x,y,v;
inline loli(){}
inline loli(R int xx,R int yy,R int vv):x(xx),y(yy),v(vv){}
inline bool operator <(const loli &b)const{return v<b.v;}
};
struct node;typedef node* ptr;
struct node{
ptr lc,rc;loli r1,r2;int t,mdv,mnv;pi pmn,smx,mx,mn;
inline void ppd(R int x){t+=x,mdv+=x,mnv+=x;}
void upd(){
mnv=min({lc->mnv,rc->mnv,lc->mdv})+t;
mdv=rc->mdv+t;
mx=max(lc->mx,rc->mx);
mn=min(lc->mn,rc->mn);
r1=loli(-1,-1,-2*inf);
r2=max(lc->r2,rc->r2);
cmax(lc->mnv+t==mnv?r1:r2,lc->r1);
cmax(rc->mnv+t==mnv?r1:r2,rc->r1);
if(lc->mdv+t!=mnv){
R pi vl=(lc->mnv+t==mnv?lc->smx:lc->mx);
R pi vr=(rc->mnv+t==mnv?rc->pmn:rc->mn);
cmax(r2,loli(vr.se,vl.se,vl.fi-vr.fi));
}
cmax(r2,loli(lc->mn.se,rc->mx.se,rc->mx.fi-lc->mn.fi));
cmax(r1,loli(rc->mn.se,lc->mx.se,lc->mx.fi-rc->mn.fi));
pmn=pi(inf,-1),smx=pi(-inf,-1);
if(lc->mnv+t==mnv)pmn=lc->pmn;
else{
pmn=lc->mn;
if(lc->mdv+t!=mnv)cmin(pmn,rc->pmn);
}
if(rc->mnv+t==mnv)smx=rc->smx;
else{
smx=rc->mx;
if(lc->mdv+t!=mnv)cmax(smx,lc->smx);
}
}
}e[N<<2],*rt,*pp=e;
pi a[N];int n;ll res;
void build(ptr &p,int l,int r){
p=++pp;
if(l==r){
p->r1=p->r2=loli(l,r,-1);
p->mn=p->pmn=p->mx=p->smx=pi(a[r].se,r);
p->t=p->mnv=p->mdv=0;
// printf("%d %d %d\n",l,r,p->mn.fi);
return;
}
int mid=(l+r)>>1;
build(p->lc,l,mid),build(p->rc,mid+1,r);
p->upd();
}
void erase(ptr p,int l,int r,int x){
if(l==r){
p->mn=p->pmn=pi(inf,r);
p->mx=p->smx=pi(-inf,r);
return;
}
int mid=(l+r)>>1;
x<=mid?erase(p->lc,l,mid,x):erase(p->rc,mid+1,r,x);
p->upd();
}
void update(ptr p,int l,int r,int ql,int qr,int d){
if(ql<=l&&qr>=r)return p->ppd(d),void();
int mid=(l+r)>>1;
if(ql<=mid)update(p->lc,l,mid,ql,qr,d);
if(qr>mid)update(p->rc,mid+1,r,ql,qr,d);
p->upd();
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d",&n);
fp(i,1,n)scanf("%d%d",&a[i].fi,&a[i].se);
sort(a+1,a+1+n),build(rt,1,n);
fp(i,1,n>>1){
R loli now=rt->r2;
if(rt->mnv)cmax(now,rt->r1);
if(now.v>0){
res+=now.v;
erase(rt,1,n,now.x),erase(rt,1,n,now.y);
if(now.x<now.y)update(rt,1,n,now.x,now.y-1,1);
else update(rt,1,n,now.y,now.x-1,-1);
}
printf("%lld\n",res);
}
return 0;
}
\(DDART\)
以后打\(cc\)再也不看中文题面了……不知道在翻什么……
由于保证了所有圆共点,所以其实就是个bzoj4140,不过要注意开始时的三个圆有两个共点的情况
感觉好难写啊……不写了……