# 省选模拟赛记录(越往下越新哦~~~)

LOG 模拟赛

T3正解是,在我的思路的基础之上,利用题目给出的随机树的条件,把我每次都要重新处理的东西记录了下来,这样像动态点分治一样每次查询加修改就可以了……

T2好神啊……

#pragma GCC optimize("O3")
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=100010;
const int P=1005060097;
inline int Pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=(LL)ret*x%P;
x=(LL)x*x%P,y>>=1;
}return ret;
}
int A[N<<2],ai[N<<2],rev[N<<2],inv[N<<2],len;
int n,m;
inline void ntt(int *C,int opt){
register int i,j,k,w;int wn,temp;
for(i=1;i<len;++i)if(rev[i]>i)std::swap(C[i],C[rev[i]]);
for(k=2;k<=len;k<<=1){
wn=Pow(5,(P-1)/k);
if(opt==-1)wn=Pow(wn,P-2);
for(i=0;i<len;i+=k){
w=1;
for(j=0;j<(k>>1);++j,w=(LL)w*wn%P){
temp=(LL)w*C[i+j+(k>>1)]%P;
C[i+j+(k>>1)]=(C[i+j]-temp+P)%P;
C[i+j]=(C[i+j]+temp)%P;
}
}
}
}
inline void get_inv(int *a,int *b,int cd){
if(cd==1){b[0]=Pow(a[0],P-2);return;}
get_inv(a,b,cd>>1),len=cd<<1;
int i,ni=Pow(len,P-2);
for(i=1;i<len;++i)rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
memcpy(A,a,cd<<2),memset(A+cd,0,cd<<2);
ntt(A,1),ntt(b,1);
for(i=0;i<len;++i)b[i]=(2-(LL)b[i]*A[i]%P+P)%P*(LL)b[i]%P;
ntt(b,-1);
for(i=0;i<cd;++i)b[i]=(LL)b[i]*ni%P;
memset(b+cd,0,cd<<2);
}
int main(){
scanf("%d%d",&n,&m);int i,x;
for(i=1;i<=m;++i)
scanf("%d",&x),++ai[x];
ai[0]=P-1,len=1;
while(len<=n)len<<=1;
get_inv(ai,inv,len);
printf("%d\n",(P-inv[n])%P);
return 0;
}
Kod

#include <cstdio>
#include <bitset>
#include <cstring>
#include <algorithm>
const int N=100010;
std::bitset<N> test,data,temp;
int n,m,cost[N],cnt[(1<<22)+10];
char s[N];
int main(){
scanf("%d%d",&m,&n);
int full=(1<<m)-1,i,j,ans=0x3f3f3f3f;
memset(cost,0x3f,sizeof(cost)),cost[0]=0;
for(i=1;i<=full;++i){
cnt[i]=cnt[i-((-i)&i)]+1;
cost[i%n]=std::min(cost[i%n],cnt[i]+1);
cost[((-i)%n+n)%n]=std::min(cost[((-i)%n+n)%n],cnt[i]);
}
for(scanf("%s",s),i=0;i<n;++i)data[i]=s[i]=='1';
for(scanf("%s",s),i=0;i<n;++i)test[i]=s[i]=='1';
for(i=0;i<n;++i){
if(i!=0)j=data[0],data>>=1,data[n-1]=j;
temp=data^test;
j=temp.count(),j=std::min(j,n-j+1);
ans=std::min(ans,j+cost[i]);
}
printf("%d\n",ans);
return 0;
}
Bitset
#include <cmath>
#include <cstdio>
#include <cstring>
#include <complex>
#include <algorithm>
typedef double db;
typedef std::complex<db> cd;
const int N=300010;
const db Pi=std::acos(-1.);
cd A[N<<2],B[N<<2];
int test[N<<2],data[N<<2],ci[N<<2],rev[N<<2],len;
int n,m,cost[N],cnt[(1<<22)+10];
char s[N];
inline void fft(cd *C,int opt){
register int i,j,k;cd temp;
for(i=1;i<len;++i)
if(rev[i]>i)
std::swap(C[rev[i]],C[i]);
for(k=2;k<=len;k<<=1){
cd wn(std::cos(2*opt*Pi/k),std::sin(2*opt*Pi/k));
for(i=0;i<len;i+=k){
cd w(1.,0.);
for(j=0;j<(k>>1);++j,w*=wn){
temp=w*C[i+j+(k>>1)];
C[i+j+(k>>1)]=C[i+j]-temp;
C[i+j]+=temp;
}
}
}
}
inline void mul(int *a,int *b,int *c,int n){
len=1;while(len<n)len<<=1;int i;
for(i=0;i<len;++i){
rev[i]=(rev[i>>1]>>1)|((i&1)?(len>>1):0);
A[i]=a[i],B[i]=b[i];
}
fft(A,1),fft(B,1);
for(i=0;i<len;++i)A[i]*=B[i];
fft(A,-1);
db inv=1./len;
for(i=0;i<len;++i)c[i]=round(A[i].real()*inv);
}
int main(){
scanf("%d%d",&m,&n);
int full=(1<<m)-1,i,j,ans=0x3f3f3f3f;
memset(cost,0x3f,sizeof(cost)),cost[0]=0;
for(i=1;i<=full;++i){
cnt[i]=cnt[i-((-i)&i)]+1;
cost[i%n]=std::min(cost[i%n],cnt[i]+1);
cost[((-i)%n+n)%n]=std::min(cost[((-i)%n+n)%n],cnt[i]);
}
for(scanf("%s",s),i=0;i<n;++i)data[i]=data[i+n]=s[i]=='1'?1:-1;
for(scanf("%s",s),i=0;i<n;++i)test[n-i-1]=s[i]=='1'?1:-1;
mul(test,data,ci,n+n+n);
for(i=0;i<n;++i){
j=(ci[i+n-1]+n)>>1;
ans=std::min(ans,cost[i]+std::min(j+1,n-j));
}
printf("%d\n",ans);
return 0;
}
fft

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1000000,P=1005060097,inv2=502530049;
#define mod(a) ((a)<P?(a):(a)%P)
char mu[N+10];
int prime[N+10],len;
bool isnot[N+10];
inline LL calc(LL lim){
LL ret=0;
for(register LL i=1,last=1;i<=lim;i=last+1){
last=lim/(lim/i);
ret=(ret+mod(i+last)*mod(last-i+1)%P*inv2%P*mod(lim/i)%P)%P;
}
return ret;
}
int main(){
register int i,j,k;
mu[1]=1;
for(i=2;i<=N;++i){
if(!isnot[i])prime[++len]=i,mu[i]=-1;
for(j=1;prime[j]*i<=N;++j){
isnot[prime[j]*i]=true;
if(i%prime[j]==0){mu[prime[j]*i]=0;break;}
mu[prime[j]*i]=-mu[i];
}
}
LL n;int ans=0;
scanf("%lld",&n);
for(k=1;(LL)k*k<=n;++k)
ans=(ans+mu[k]*k*calc(n/((LL)k*k))%P+P)%P;
ans=(ans-(n%P)*((n+1)%P)%P*inv2%P+P)%P;
printf("%d\n",ans);
return 0;
}

No.11省选模拟测试
T1:

T2:

T3:

No.12省选模拟测试
T1:

T2:

T3:

No.14省选模拟测试

T1,莫名奇妙地80,这个东西的思路就是状态转移.有两种方法,第一种是从已知状态向后逆转移,十分清真好理解,第二种是对于每一种状态去搜索其能到达的所有状态从而转移,这种方法十分玄学,而且还容易错,我现在也不是很懂他那个谜一样的环的处理办法……

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=7010;
int n,st[2][N],degree[2][N],f[2][N],q[N<<1],front,back;
int main(){
register int i;
for(int id=0;id<2;++id){
for(i=1;i<=st[id][0];++i)
for(i=1;i<=n;++i)
degree[id][i]=st[id][0];
}
f[0][1]=f[1][1]=-1;
q[back++]=1,q[back++]=-1;
register int x,y,u,v;
while(front!=back){
x=q[front++];
if(x<0)y=-x,x=1,u=0;
else y=x,x=0,u=1;
if(f[x][y]>0)
for(i=1;i<=st[u][0];++i){
v=(y+st[u][i]-1)%n+1;
if(f[u][v])continue;
if(!(--degree[u][v]))
f[u][v]=-1,q[back++]=u?-v:v;
}
else
for(i=1;i<=st[u][0];++i){
v=(y+st[u][i]-1)%n+1;
if(f[u][v])continue;
f[u][v]=1,q[back++]=u?-v:v;
}
}
for(int id=0;id<2;++id){
for(i=2;i<=n;++i){
if(f[id][i]==1)printf("Win ");
else if(f[id][i]==-1)printf("Lose ");
else printf("Loop ");
}
puts("");
}
return 0;
}
Kod

T2,我没想出来的那个部分分完全可以用补集转化加矩阵树解决……正解好神啊,矩阵树加生成函数.结合基尔霍夫矩阵的那个结论,我们求出来的主子式行列式就是其所有生成树的边权之积的和.那么如果把原树边的值设为1,把非原树边的值设为x,那么我们的主子式行列式是一个多项式,其前k+1项的和,就是我们的答案.而直接这样求不是很好,那么我们就带入n个值求出对应的答案,利用拉格朗日插值或者高斯消元解方程组来得到多项式系数.

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=85;
const int P=1000000007;
inline int Pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=(LL)ret*x%P;
x=(LL)x*x%P,y>>=1;
}
return ret;
}
inline int Inv(int x){
return Pow(x,P-2);
}
int n,cao,v[N][N],g[N],co[N],ans[N];
struct Matrix{
int a[N][N];
inline void clear(){
memset(a,0,sizeof(a));
}
inline void add(int x,int y,int z){
a[x][x]+=z,a[y][y]+=z;
a[x][y]-=z,a[y][x]-=z;
}
inline int kir(){
int ret=1,b,inv;
register int i,j,k;
for(i=1;i<n;++i)
for(j=1;j<n;++j)
a[i][j]=(a[i][j]%P+P)%P;
for(i=1;i<n;++i){
if(a[i][i]==0){
for(j=i+1;j<n;++j)
if(a[j][i]){
for(k=i;k<n;++k)
std::swap(a[i][k],a[j][k]);
break;
}
ret=(P-ret)%P;
}
inv=Inv(a[i][i]);
for(j=i+1;j<n;++j){
b=(LL)a[j][i]*inv%P;
for(k=i;k<n;++k)
a[j][k]=(a[j][k]-(LL)b*a[i][k]%P+P)%P;
}
ret=(LL)ret*a[i][i]%P;
}
return ret;
}
}Kir;
int main(){
scanf("%d%d",&n,&cao);
register int i,j,k;
for(i=1;i<n;++i){
scanf("%d",&j);
v[i][j]=v[j][i]=1;
}
for(i=0;i<n;++i){
if(i==0){
co[i]=1;
continue;
}
Kir.clear();
for(j=0;j<n;++j)
for(k=j+1;k<n;++k)
co[i]=Kir.kir();
}
int b,c,l;
for(i=0;i<n;++i){
memset(g,0,sizeof(g));
b=co[i],l=1,g[0]=1;
for(j=0;j<n;++j){
if(j==i)continue;
b=(LL)b*Inv((i-j+P)%P)%P;
c=(P-j)%P;
for(k=l;k>0;--k)
g[k]=((LL)g[k]*c%P+g[k-1])%P;
g[0]=(LL)g[0]*c%P;
++l;
}
for(j=0;j<n;++j)
ans[j]=(ans[j]+(LL)g[j]*b)%P;
}
for(i=0;i<=cao;++i)
return 0;
}
Kod

T3,这题真好,只不过我的那30分呢,明明本机可以50的啊……以后还是把本机测试速度当作参考吧,实际复杂度才是最能说明问题的,毕竟评测环境不同,速度也不同嘛.在我的做法里把我用set搞的东西全部用链表处理出来就可以70了,再稍微卡卡常数(似乎还有分块排序这种卡常操作)就可以A掉了……利用KD_tree,把询问看作点,每个点看作对一个矩形的操作,应该就能50分,但是如果把点按照从大到小的顺序进行操作,再加上一些打标记的技巧,会更加得稳……正解的话,好神啊……我感觉这题在前两个部分分里加入权值随机的条件就有一些暗示……我们从点对的角度观察性质,或者说从一个点的贡献的角度,就会发现对于一个点i,大于它的j,可能和他做出贡献的j的a一定是单调的,而且对于值大于他的和值小于他的j,单调性不同.只是利用这个性质话,可以在随机权值中get到50分,因为据说随机权值下,对于一个点,他后面的点单调起来的个数是logw的.我们继续观察,同时强化我们的式子,就可以得到题解的最终的做法,十分好打.

#include <set>
#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS,*xT;
template <typename _t>
register char ch=gtc;bool ud=false;
for(x=0;ch<'0'||ch>'9';ch=gtc)if(ch=='-')ud=true;
for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc);
if(ud)x=-x;
}
typedef long long LL;
typedef std::multiset<int> msi;
typedef std::multiset<int>::iterator mit;
const int L=150;
const int C=100010;
const int N=100010;
const int M=1000010;
const int oo=1000000000;
const int Inf=0x7f7f7f7f;
msi st;
mit re[L<<1];
int len;
int n,m,ans[M],a[N],pos[N],cnt,min;
struct Q{
int l,r,id;
}q[M];
inline bool comp(Q aa,Q bb){
return pos[aa.l]<pos[bb.l]||(pos[aa.l]==pos[bb.l]&&aa.r<bb.r);
}
inline mit ins(int key){
mit ret,tmp,it;
ret=tmp=it=st.insert(key);
++tmp;
min=std::min(min,std::abs(key-*tmp));
--it;
min=std::min(min,std::abs(key-*it));
return ret;
}
inline int force_query(int l,int r){
if(r-l+1<=50){
register int i,j,ret=Inf;
for(i=l;i<=r;++i)
for(j=i+1;j<=r;++j)
ret=std::min(ret,std::abs(a[i]-a[j]));
return ret;
}
min=Inf,st.clear();
st.insert(Inf),st.insert(oo-Inf);
for(register int i=l;i<=r;++i)
ins(a[i]);
return min;
}
inline int round_query(int aim){
int p=pos[aim]*L+1,ret=min;
len=0;
while(p!=aim)
re[++len]=ins(a[--p]);
std::swap(ret,min);
for(int i=1;i<=len;++i)
st.erase(re[i]);
return ret;
}
inline void quick_query(int l,int r){
min=Inf,st.clear();
st.insert(Inf),st.insert(oo-Inf);
register int i,p=pos[q[l].l]*L;
for(i=l;i<=r;++i){
while(p!=q[i].r)ins(a[++p]);
ans[q[i].id]=round_query(q[i].l);
}
}
int main(){
register int i,l,r;
for(i=1;i<=n;++i)
for(i=1;i<=m;++i){
if(r-l+1<=L)ans[i]=force_query(l,r);
else q[++cnt]=(Q){l,r,i};
}
std::sort(q+1,q+(cnt+1),comp);
for(l=1,r=l;l<=cnt;l=r+1,r=l){
while(r+1<=cnt&&pos[q[l].l]==pos[q[r+1].l])++r;
quick_query(l,r);
}
for(i=1;i<=m;++i)
printf("%d\n",ans[i]);
return 0;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS,*xT;
template <typename _t>
register char ch=gtc;bool ud=false;
for(x=0;ch<'0'||ch>'9';ch=gtc)if(ch=='-')ud=true;
for(;ch>='0'&&ch<='9';x=(x<<1)+(x<<3)+ch-'0',ch=gtc);
if(ud)x=-x;
}
const int L=100,N=100010,M=1000010,oo=1000000000,Inf=0x7f7f7f7f;
#define del(i) (lq[lh[a[i]]]=lq[a[i]],lh[lq[a[i]]]=lh[a[i]])
#define ins(i) (lq[lh[a[i]]]=a[i],lh[lq[a[i]]]=a[i])
#define get(i) (val[i]=std::min(std::abs(key[lq[a[i]]]-key[a[i]]),std::abs(key[lh[a[i]]]-key[a[i]])))
int n,a[N],key[N],temp[N],pos[N];
int lq[N],lh[N];
int val[N],min[N];
inline void Init(){
for(register int i=1;i<=n;++i)
lq[i]=i-1,lh[i]=i+1;
lh[0]=1,lq[n+1]=n;
}
inline bool comp1(int x,int y){return a[x]<a[y];}
struct Q{int l,r,id;}q[M];
int m,ans[M],cnt;
inline bool comp2(Q aa,Q bb){
return pos[aa.l]<pos[bb.l]||(pos[aa.l]==pos[bb.l]&&aa.r>bb.r);
}
inline int force_query(int l,int r){
register int i,len=0,ret=Inf;
for(i=l;i<=r;++i)
temp[++len]=key[a[i]];
std::sort(temp+1,temp+(len+1));
for(i=1;i<len;++i)
ret=std::min(ret,temp[i+1]-temp[i]);
return ret;
}
inline void quick_query(int l,int r){
memset(min,0x7f,sizeof(min));
register int i,j,p=pos[q[l].l]*L,wq=n,tmp;
Init();
for(i=1;i<=p;++i)del(i);
for(i=n;i>p;--i)get(i),del(i);
for(i=p+1;i<=n;++i)min[i]=std::min(min[i-1],val[i]);
Init();
for(i=1;i<=p-L;++i)del(i);
for(i=l;i<=r;++i){
while(wq!=q[i].r)del(wq),--wq;
tmp=min[q[i].r];
for(j=p-L+1;j<=p;++j)get(j),del(j);
for(j=p;j>p-L;--j)ins(j);
for(j=p;j>=q[i].l;--j)tmp=std::min(tmp,val[j]);
ans[q[i].id]=tmp;
}
}
int main(){
register int i,l,r;
std::sort(temp+1,temp+(n+1),comp1);
for(i=1;i<=n;++i)key[i]=a[temp[i]],a[temp[i]]=i;
key[0]=oo-Inf,key[n+1]=Inf;
for(i=1;i<=m;++i){
if(pos[l]==pos[r])ans[i]=force_query(l,r);
else q[++cnt]=(Q){l,r,i};
}
std::sort(q+1,q+(cnt+1),comp2);
for(l=1,r=l;l<=cnt;l=r+1,r=l){
while(r+1<=cnt&&pos[q[l].l]==pos[q[r+1].l])++r;
quick_query(l,r);
}
for(i=1;i<=m;++i)
printf("%d\n",ans[i]);
return 0;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
char xB[(1<<15)+10],*xS,*xT;
R char ch=gtc;
for(x=0;ch<'0'||ch>'9';ch=gtc);
for(;ch>='0'&&ch<='9';x=(x*10)+ch-'0',ch=gtc);
}
const int N=100010,M=N*10,oo=1e9,Inf=0x7f7f7f7f;
struct Segment_Tree{
Segment_Tree *ch[2];
int min;
Segment_Tree(){ch[0]=ch[1]=NULL,min=Inf;}
inline void* operator new(size_t);
}*C,*mempool,*root;
inline void* Segment_Tree::operator new(size_t){
if(C==mempool){
C=new Segment_Tree[(1<<17)+10];
mempool=C+(1<<17)+10;
}
return C++;
}
#define mid ((l+r)>>1)
inline void insert(Segment_Tree *&p,int l,int r,int pos,int key){
if(!p)p=new Segment_Tree;
p->min=std::min(p->min,key);
if(l==r)return;
if(pos<=mid)insert(p->ch[0],l,mid,pos,key);
else insert(p->ch[1],mid+1,r,pos,key);
}
inline int query(Segment_Tree *p,int l,int r,int z,int y){
if(!p)return Inf;
if(z<=l&&r<=y)return p->min;
int ret=Inf;
if(z<=mid)ret=std::min(ret,query(p->ch[0],l,mid,z,y));
if(mid<y)ret=std::min(ret,query(p->ch[1],mid+1,r,z,y));
return ret;
}
int n,m,ans[M],tree[N],a[N];
struct Qu{int l,r,id;}q[M];
inline bool comp(Qu aa,Qu bb){return aa.l<bb.l;}
inline void U(R int pos,int key){
for(;pos<=n;pos+=pos&(-pos))
tree[pos]=std::min(tree[pos],key);
}
inline int Q(R int pos){
R int ret=Inf;
for(;pos>0;pos-=pos&(-pos))
ret=std::min(ret,tree[pos]);
return ret;
}
inline void work(){
root=NULL;
memset(tree,0x7f,sizeof(tree));
std::sort(q+1,q+(m+1),comp);
R int i,get,pos=m;
for(i=n;i>0;--i){
get=query(root,0,oo,a[i],oo);
while(get<=n){
U(get,a[get]-a[i]);
get=query(root,0,oo,a[i],((a[i]+a[get])>>1)-1);
}
insert(root,0,oo,a[i],i);
while(pos&&q[pos].l==i)
ans[q[pos].id]=std::min(ans[q[pos].id],Q(q[pos].r)),--pos;
}
}
inline void rev(){
std::reverse(a+1,a+n+1);
for(R int i=1;i<=m;++i){
q[i].l=n-q[i].l+1,q[i].r=n-q[i].r+1;
std::swap(q[i].l,q[i].r);
}
}
int main(){
R int i,l,r;
for(i=1;i<=m;++i){
q[i]=(Qu){l,r,i};
ans[i]=Inf;
}
work(),rev(),work();
for(i=1;i<=m;++i)
printf("%d\n",ans[i]);
return 0;
}

I.傍若无人,不要受周围人的影响
II.数据结构题,速战速决,不要让他占用太多的时间
III.想尽办法提升考试状态

T1用的时间太长了,正解1k,我4k.我打了一个线段树启发式合并,我的题解+Kod:

#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
char xB[(1<<15)+10],*xS,*xT;
R char ch=gtc;
for(x=0;ch<'0'||ch>'9';ch=gtc);
for(;ch>='0'&&ch<='9';x=(x*10)+ch-'0',ch=gtc);
}
const int N=200010;
struct V{
int to,next;
}c[N<<1];
}
int keep[N],kk[N],len;
struct Segment_Tree{
Segment_Tree *ch[2];
int max;
Segment_Tree(){ch[0]=ch[1]=NULL,max=0;}
inline void pushdown(){
if(!max)return;
if(ch[0])ch[0]->max+=max;
if(ch[1])ch[1]->max+=max;
max=0;
}
inline void* operator new(size_t);
}*root[N],*C,*mempool;
inline void* Segment_Tree::operator new(size_t){
if(C==mempool){
C=new Segment_Tree[(1<<16)+10];
mempool=C+(1<<16)+10;
}
return C++;
}
#define mid ((l+r)>>1)
inline void insert(Segment_Tree *&p,int l,int r,int pos,int key){
if(!p)p=new Segment_Tree;
if(l==r){p->max=key;return;}
p->pushdown();
if(pos<=mid)insert(p->ch[0],l,mid,pos,key);
else insert(p->ch[1],mid+1,r,pos,key);
}
inline void add_up(Segment_Tree *p,int l,int r,int z,int y,int key){
if(!p)return;
if(z<=l&&r<=y){p->max+=key;return;}
p->pushdown();
}
inline void dfs(Segment_Tree *p,int l,int r){
if(!p)return;
if(l==r){keep[++len]=l,kk[len]=p->max;return;}
p->pushdown();
dfs(p->ch[0],l,mid);
dfs(p->ch[1],mid+1,r);
}
inline int lb(Segment_Tree *p,int l,int r,int pos){
if(!p)return 0;
if(l==r)return p->max;
R int ret;
p->pushdown();
if(pos<=mid){
ret=lb(p->ch[0],l,mid,pos);
if(ret==0&&p->ch[1])ret=lb(p->ch[1],mid+1,r,pos);
}
else ret=lb(p->ch[1],mid+1,r,pos);
return ret;
}
inline int pb(Segment_Tree *p,int l,int r,int pos){
if(!p)return 0;
if(l==r)return p->max;
R int ret;
p->pushdown();
if(pos<=mid)ret=pb(p->ch[0],l,mid,pos);
else{
ret=pb(p->ch[1],mid+1,r,pos);
if(ret==0&&p->ch[0])ret=pb(p->ch[0],l,mid,pos);
}
return ret;
}
inline int del(Segment_Tree *&p,int l,int r,int pos){
if(!p)return 0;
if(l==r){p=NULL;return l;}
R int ret;
if(pos<=mid)ret=del(p->ch[0],l,mid,pos);
else{
ret=del(p->ch[1],mid+1,r,pos);
if(ret==0&&p->ch[0])ret=del(p->ch[0],l,mid,pos);
}
if(p->ch[0]==NULL&&p->ch[1]==NULL)p=NULL;
return ret;
}
int n,m,size[N],a[N],b[N],pos[N];
inline bool comp(int x,int y){return a[x]<a[y];}
inline void dfs(int x,int fa){
R int i,j,last,temp;
if(c[i].to==fa)continue;
dfs(c[i].to,x);
if(size[x]<size[c[i].to])std::swap(root[x],root[c[i].to]);
len=0,dfs(root[c[i].to],1,m);
size[x]+=size[c[i].to];
for(j=1,last=1;j<=len;++j){
temp=lb(root[x],1,m,keep[j]);
insert(root[x],1,m,keep[j],kk[j]+temp);
last=keep[j]+1;
}
}
i=lb(root[x],1,m,b[x])+1;
insert(root[x],1,m,b[x],i);
last=b[x]-1;
while(last){
temp=pb(root[x],1,m,last);
if(temp==0||temp>=i)break;
last=del(root[x],1,m,last)-1;
}
++size[x];
}
int main(){
R int i,x,y;
for(i=1;i<=n;++i)
std::sort(pos+1,pos+(n+1),comp);
for(i=1;i<=n;++i){
if(i==1||a[pos[i]]!=a[pos[i-1]])++m;
b[pos[i]]=m;
}
for(i=1;i<n;++i){
}
dfs(1,0);
int ans=n-lb(root[1],1,m,1);
printf("%d\n",ans);
return 0;
}
Kod

#include <map>
#include <vector>
#include <cstdio>
#define pb push_back
#define ft first
#define sd second
const int N=200010;
int n,a[N];
std::vector<int> g[N];
std::map<int,int> f[N];
inline void dfs(int x,int fa){
for(auto p:g[x])
if(p!=fa){
dfs(p,x);
if(f[x].size()<f[p].size())f[x].swap(f[p]);
for(auto q:f[p])f[x][q.ft]+=q.sd;
}
++f[x][a[x]];
auto it=f[x].find(a[x]);
if(it!=f[x].begin()){
--it,--it->sd;
if(!it->sd)f[x].erase(it);
}
}
int main(){
int i,x,y;
for(i=1;i<n;++i){
g[x].pb(y),g[y].pb(x);
}
dfs(1,0);
int ans=n;
for(auto p:f[1])ans-=p.sd;
printf("%d\n",ans);
return 0;
}
Kod

I.从链推广到树是一用由简单到复杂的思考方式,十分值得借鉴.
II.利用单调性与维护单调性的方式,是一个值得思考的事情,
III.差分似乎与单调性有什么联系.
IV.差分解决问题好像十分有效,之前遇到过的差分异或、差分转置换、树上差分、差分概率等等,都十分巧妙.

I.map、set的swap可以O(1)交换两个容器里的全部内容.
II.神奇的auto,我并不会用.
*III.排序的启发式合并会变快?
T2考试的时候没仔细想,赛后想想另外30分,并不难,在有了另外30分的思想基础后,正解也并不难……

#include <cstdio>
#include <cstring>
#include <algorithm>
#define R register
typedef long long LL;
char xB[(1<<15)+10],*xS,*xT;
R char ch=gtc;
for(x=0;ch<'0'||ch>'9';ch=gtc);
for(;ch>='0'&&ch<='9';x=(x*10)+ch-'0',ch=gtc);
}
const int N=200010;
const int P=1000000007;
const int inv2=500000004;
struct Seg{
int l,r,key;
}seg[N];
inline bool comp(Seg a,Seg b){
return a.key<b.key;
}
int n,m,size,a[N],pr[N],nt[N],cnt[N],sum,ji[N],ou[N];
#define SUM(a) ((LL)(a)*((a)+1)/2)
inline void insert(int l,int r){
R int z=l,y=r,len;
if(pr[l-1]!=-1){
z=pr[l-1],len=l-pr[l-1];
sum=(sum-ji[len]+P)%P;
}
if(nt[r+1]!=-1){
y=nt[r+1],len=nt[r+1]-r;
sum=(sum-ji[len]+P)%P;
}
len=y-z+1;
pr[y]=z,nt[z]=y;
sum=(sum+ji[len])%P;
}
inline int modify(){
R LL ret=sum;
if(nt[1]!=-1&&pr[n]!=-1){
R int l,r;
l=nt[1],r=n-pr[n]+1;
ret=ret-ji[l]-ji[r]+SUM(l);
if((--l)>r)std::swap(l,r);
r=l+r,l=r-l-l;
ret=ret+ou[r]-ou[l]+ji[l];
ret%=P;
}
return ret;
}
int main(){
R int i,j,k;
ji[0]=0,ou[0]=0,ou[1]=1;
for(i=2;i<=n;++i)ou[i]=(ou[i-2]+SUM(i))%P;
memset(pr,-1,sizeof(pr));
memset(nt,-1,sizeof(nt));
for(i=1,j=1;i<=n;i+=j,j=1){
while(i+j<=n&&a[i+j]==a[i])++j;
seg[++m]=(Seg){i,i+j-1,a[i]};
}
std::sort(a+1,a+(n+1));
std::unique(a+1,a+(n+1));
std::sort(seg+1,seg+(m+1),comp);
for(i=1,j=1;i<=m;i+=j,j=1){
while(i+j<=m&&seg[i+j].key==seg[i].key)++j;
if(i+j>m)break;
++size;
for(k=i;k<i+j;++k)
insert(seg[k].l,seg[k].r);
cnt[size]=modify();
}
++size;
cnt[size]=(LL)n*(n+1)/2%P;
cnt[size]=(LL)cnt[size]*(cnt[size]+1)%P*inv2%P;
R int ans=0;
for(i=1;i<=size;++i)
ans=(ans+(LL)(cnt[i]-cnt[i-1]+P)*a[i])%P;
printf("%d\n",ans);
return 0;
}
Kod

T3考试的时候没深入推,其实深入推也不会发生更多的事情……

#include <cstdio>
typedef long long LL;
const LL N=200010,P=100003;
LL n,m,jie[P],ni[P],A,B,C,f[5][2];
#define c(n,m) (m>n?0:jie[n]*ni[m]%P*ni[n-m]%P)
int main(){
scanf("%lld%lld",&n,&m);
A=(n+m)>>1,B=(n-m)>>1,C=A+B;
ni[0]=jie[0]=1,ni[P-1]=P-1;
LL i,j,num,t,a;
for(i=1;i<P;++i)jie[i]=jie[i-1]*i%P;
for(i=P-2;i>0;--i)ni[i]=ni[i+1]*(i+1)%P;
f[0][0]=1;
for(i=1;i<=4;++i){
num=C%P,C/=P,a=A%P,A/=P;
for(j=0;j<=a;++j){
f[i][(t=num-j)<0]=(f[i][t<0]+f[i-1][0]*c(a,j)*c((t+(t<0?P:0)),a))%P;
f[i][(--t)<0]=(f[i][t<0]+f[i-1][1]*c(a,j)*c((t+(t<0?P:0)),a))%P;
}
}
printf("%lld\n",f[4][0]);
return 0;
}
Kod

I.Lucas定理好像除了计算组合数以外,还能将其本身作为解题的工具.
II.推式子的时候式子的美观程度也是很重要的.
III.像这道题一样转换坐标系的方法是值得积累的.
IV.利用组合数本身的性质去刨去卡上界的步骤是很妙的.
V.记录是否借位似乎很妙的样子.
VI.数位dp也可以很活.

I.时间分配,速战速决
II.心态良好,临危不乱

I.读题要准,要快.
II.打暴力要快.
III.不要在一个没什么规律的表上耗费太多的时间.
IV.不要对一道题投入太少.
V.要有信仰.
VI.考试的时候一定要冷静,不要把时间复杂度计算错误.
VII.基础算法要掌握牢啊.
T1是个神题.
T2十分巧妙,我的40分暴力就不说了,下一个部分分,也就是70分做法,是推一下式子,发现我们的pos在前后都会满足一个式子,并且结合原来的暴力得知pos是唯一的,于是枚举pos,进行O(n^2)的dp,于是总复杂度为O(n^3).正解是在这个做法的基础之上进行巧妙的问题转化,将我们的贡献计算公式转化为组合问题(染色问题或选取元素问题),从而使得我们本来的瓶颈(我们的限制条件对于pos来说一定要从pos向两边走,从而使得我们的dp不得不每次重新开始)得以解决,也就是说我们只需要进行O(1)次O(n^2)的dp,同时为了方便计算,正解还引入了一些新的定义,最终使得我们可以在O(n^2)的时间内得到答案.

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=2010;
const int P=1000000007;
int n,ans,a[N];
int f0[N][N],f1[N][N],g0[N][N],g1[N][N],g2[N][N];
inline void Init(){
register int i;
for(i=1;i<=n;++i)
f0[0][0]=1;
g0[n+1][0]=1;
}
inline void dp(){
register int i,j,k;
for(i=1;i<=n;++i)
for(j=0;j<=i;++j){
if(a[i]){
k=std::max(2,j+1);
f0[i][k]=(f0[i][k]+f0[i-1][j])%P;
f1[i][k]=(f1[i][k]+f1[i-1][j])%P;
}
if(a[i]<=0){
k=std::max(0,j-1);
f0[i][k]=(f0[i][k]+f0[i-1][j])%P;
f1[i][k]=((LL)f1[i][k]+f0[i-1][j]+f1[i-1][j])%P;
}
}
for(i=n;i>0;--i)
for(j=0;j<=(n-i);++j){
if(a[i]){
k=std::max(0,j-1);
g0[i][k]=(g0[i][k]+g0[i+1][j])%P;
g1[i][k]=((LL)g1[i][k]+g0[i+1][j]+g1[i+1][j])%P;
g2[i][k]=((LL)g2[i][k]+g1[i+1][j]*2+g2[i+1][j]+g0[i+1][j])%P;
}
if(a[i]<=0){
k=j+1;
g0[i][k]=(g0[i][k]+g0[i+1][j])%P;
g1[i][k]=(g1[i][k]+g1[i+1][j])%P;
g2[i][k]=(g2[i][k]+g2[i+1][j])%P;
}
}
}
inline void print(){
for(register int i=0;i<=n;++i)
ans=(ans+(LL)f0[i][0]*g2[i+1][0]+(LL)f1[i][0]*g1[i+1][0])%P;
printf("%d\n",ans);
}
int main(){
Init(),dp(),print();
return 0;
}
Kod

I.又是一次找限制条件,我又没发现,从限制条件入手和发掘题目信息似乎有点像,都很重要啊.
II.我的dp好弱啊……
III.找准问题瓶颈在一定程度上有利于解题.
IV.问题转化,尤其是将抽象问题转化为组合问题,似乎很妙的样子.
V.对于dp状态,引入新的定义似乎会带来新的方向.
T3这题的数据真是水……作为一只字符串弱鸡,拿到这些分数已经很庆幸了……正解据说的SAM,但是由于题解很唬,std更唬,聪明的OIer们就自己YY了另外一种解法,不知道和正解比起来谁更优秀,总之是一种时空复杂度应该都合法的做法,反正在现有数据范围下跑得挺快.我的思路,和我后来想的kmp,以及看到题解之后YY的SAM,都无法避免每一个贡献都切切实实得去给一个O(1)的时间,这样,时间复杂度都和我的暴力是一样的.但是呢,wxh想到了用二分+hash来一次跑多个贡献,但是由于串数问题,还是过不了,不过zzh提到了Trie树,然后zyf提议Trie树hash,所以就有了一种O(n*logn*hash_table)时间复杂度的做法,感觉很优秀,于是所有人都用这种方法过掉了这题,正解凉凉了……

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
typedef unsigned long long ULL;
const int N=100010,M=300010,P=1000000007,mod=612497;
const ULL K=199;
struct Hash_Table{
int next,key;
ULL hash;
void insert(ULL hash,int key){
int pos=hash%mod;
}
bool count(ULL hash){
return true;
return false;
}
int give(ULL hash){
}
}hash_table;
struct Trie{
Trie *ch[5];
int cnt;
}node[M],*root;
int sz;
#define newnode (node+(sz++))
inline void Init(){root=newnode;}
char z[N],t[M];
int n,m,a[N],b[N];
ULL zi[N],fi[N],cf[N];
inline char check(char ch){
switch(ch){
case 'A':return 1;
case 'C':return 2;
case 'G':return 3;
case 'T':return 4;
}
}
inline void insert(char *s){
register int i,l=strlen(s+1);
register Trie *p=root;
for(i=1;i<=l;++i){
s[i]=check(s[i]);
if(!p->ch[s[i]])p->ch[s[i]]=newnode;
p=p->ch[s[i]],++p->cnt;
}
}
inline void dfs(Trie *p,int sum,ULL hash){
if(!p)return;
sum+=p->cnt;
if(sum)hash_table.insert(hash,sum);
for(int i=1;i<=4;++i)
dfs(p->ch[i],sum,hash*K+i);
}
#define get_hash(a,b,c) (a[c]-a[b-1]*cf[c-b+1])
inline void full_in(int *ai,ULL *ki){
register int i,l,r,mid,ans;
for(i=1;i<=n;++i){
l=i,r=n,ans=0;
while(l<=r){
mid=(l+r)>>1;
if(hash_table.count(get_hash(ki,i,mid)))ans=mid,l=mid+1;
else r=mid-1;
}
if(ans)ai[i]=hash_table.give(get_hash(ki,i,ans));
}
}
int main(){
Init();
scanf("%s",z+1);
n=strlen(z+1);
register int i,ans=0;
for(i=1;i<=n;++i)
z[i]=check(z[i]),zi[i]=zi[i-1]*K+z[i];
cf[0]=1;
for(i=1;i<=n;++i)
fi[i]=fi[i-1]*K+z[n-i+1],cf[i]=cf[i-1]*K;
scanf("%d",&m);
for(i=1;i<=m;++i)
scanf("%s",t+1),insert(t);
dfs(root,0,0);
full_in(a,zi),full_in(b,fi);
for(i=1;i<=n;++i)
ans=(ans+(LL)a[i]*b[n-i+2])%P;
printf("%d\n",ans);
return 0;
}
Kod

I.哈希Trie树好像很优秀的样子,但是我还不是特别清楚这玩意是啥,好像是用来查询一个串是否是Trie树前缀的?
II.找到问题瓶颈,并以其为方向去思考,并努力解决他,是一个不错的解决问题的方式.
III.hash的时候模数的选取影响效果,进制数的选取仍然影响效果.
IV.字符串匹配问题上数组也是一种不错的方法.

T1,我TM在迅速码上判断无解的部分的时候,忘了改原来的输出了,结果跑了两边dinic,只拿到了无解的分,这和直接输出-1是一个分啊,凑.

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=110;
const int M=2510;
const LL Inf=1e17;
struct V{
int to,next;
LL f;
}c[M<<2];
inline void add(int x,int y,LL z){
}
int q[N],front,back;
int deep[N];
int n,m;
inline bool bfs(){
memset(deep,-1,sizeof(deep));
deep[1]=1;
front=back=0;
q[back++]=1;
register int i,x;
while(front!=back){
x=q[front++];
if(c[i].f&&deep[c[i].to]==-1){
deep[c[i].to]=deep[x]+1;
if(c[i].to==n)return true;
q[back++]=c[i].to;
}
}
return false;
}
inline LL dfs(int x,LL v){
if(x==n||v==0)return v;
register LL ret=0,f;
if(c[i].f&&deep[c[i].to]==deep[x]+1){
f=dfs(c[i].to,std::min(c[i].f,v));
ret+=f,v-=f,c[i].f-=f,c[i^1].f+=f;
if(!v)break;
}
if(!ret)deep[x]=-1;
return ret;
}
inline LL dinic(){
LL ret=0;
while(bfs())ret+=dfs(1,Inf);
return ret;
}
int main(){
register int i,x,y,z;
for(i=1;i<=m;++i){
}
LL ans=dinic();
if(ans>=Inf)puts("-1");
else printf("%lld\n",ans);
return 0;
}
Kod

T2,我的暴力是错的,但是我看到的那个10分,其实是考察的对n==1的特判啊!

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1000;
const int P=105225319;
const int inv2=52612660;
int n,m,mi[N*N+10],c[N+10][N+10],g[N+10],f[N+10],ans[N+10];
int main(){
scanf("%d%d",&n,&m);
if(n==1){puts("0");return 0;}
register int i,j;
c[0][0]=1;
for(i=1;i<=n;++i){
c[i][0]=1;
for(j=1;j<=i;++j)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
}
mi[0]=1,++m,j=n*n;
for(i=1;i<=j;++i)
mi[i]=(LL)mi[i-1]*m%P;
g[0]=f[0]=ans[0]=1,f[1]=2;
for(i=1;i<=n;++i)
for(j=0;j<=i;++j)
g[i]=(g[i]+(LL)c[i][j]*mi[(i-j)*j])%P;
for(i=2;i<=n;++i){
for(j=1;j<i;++j)
f[i]=(f[i]+(LL)c[i-1][j-1]*f[j]%P*g[i-j])%P;
f[i]=(g[i]-f[i]+P)%P;
}
for(i=1;i<=n;++i){
f[i]=(LL)f[i]*inv2%P;
for(j=1;j<=i;++j)
ans[i]=(ans[i]+(LL)c[i-1][j-1]*f[j]%P*ans[i-j])%P;
}
printf("%d\n",ans[n]);
return 0;
}
Kod

T3,只要知道一些LCT就很好想,有一些小坑的码农题,据说jcy有用一个LCT解决的办法,但是似乎很屎,不如写俩(其实是,写一个,粘一个).

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=100010;
struct V{int to,next;}c[N<<1];
LL ans1[N];
int n,m,ans2[N],ans3[N],opt[N],poi[N];
char s[100];
}
namespace work1{
struct splay{
splay *ch[2],*f;
int rev;
int size_of_void_son;
LL ans_of_void_son;
int size_of_all_son;
LL ans_of_all_son;
inline void pushup(){
size_of_all_son=size_of_void_son+ch[0]->size_of_all_son+ch[1]->size_of_all_son;
ans_of_all_son=ans_of_void_son+ch[0]->ans_of_all_son+ch[1]->ans_of_all_son;
}
inline void mark(){
rev^=1;
std::swap(ch[0],ch[1]);
}
inline void pushdown(){
if(!rev)return;
ch[0]->mark();
ch[1]->mark();
rev=0;
}
}*null,node[N];
inline int isroot(splay *p){
return p->f->ch[0]!=p&&p->f->ch[1]!=p;
}
inline int get(splay *p){
return p->f->ch[1]==p;
}
inline void dig(splay *p){
if(isroot(p)){
p->pushdown();
return;
}
dig(p->f);
p->pushdown();
}
inline void rotate(splay *p){
splay *fa=p->f,*pa=fa->f;
int j=get(p);
if(!isroot(fa))pa->ch[get(fa)]=p;
if((fa->ch[j]=p->ch[j^1])!=null)fa->ch[j]->f=fa;
fa->f=p,p->ch[j^1]=fa,p->f=pa;
fa->pushup();
p->pushup();
}
inline void spaly(splay *p){
dig(p);
for(splay *fa=p->f;!isroot(p);rotate(p),fa=p->f)
if(!isroot(fa))
rotate(get(fa)==get(p)?fa:p);
}
inline void expose(splay *x){
splay *y=null;
while(x!=null){
spaly(x);
x->size_of_void_son-=y->size_of_all_son;
x->ans_of_void_son-=y->ans_of_all_son+y->size_of_all_son;
y->pushup();
std::swap(x->ch[1],y);
x->size_of_void_son+=y->size_of_all_son;
x->ans_of_void_son+=y->ans_of_all_son+y->size_of_all_son;
y=x;
x=x->f;
}
y->pushup();
}
inline void make_root(splay *p){
expose(p),spaly(p),p->mark();
}
inline void dfs(int x,int fa){
node[x].f=node+fa;
node[x].ch[0]=node[x].ch[1]=null;
node[x].size_of_void_son=1;
node[x].ans_of_void_son=1;
if(c[i].to!=fa){
dfs(c[i].to,x);
node[x].size_of_void_son+=node[c[i].to].size_of_all_son;
node[x].ans_of_void_son+=node[c[i].to].ans_of_all_son+node[c[i].to].size_of_all_son;
}
node[x].pushup();
}
inline void Init(){
null=node;
null->ch[0]=null->ch[1]=null->f=null;
dfs(1,0);
}
inline void Main(){
Init();
register int i,x;
splay *p;
for(i=1;i<=m;++i){
switch(opt[i]){
case 1:
expose(node+poi[i]);
break;
case 2:
make_root(node+poi[i]);
break;
case 3:
p=node+poi[i],spaly(p);
ans1[i]=p->ch[1]->ans_of_all_son+p->ans_of_void_son;
ans2[i]=p->ch[1]->size_of_all_son+p->size_of_void_son;
break;
}
}
}
}
namespace work2{
struct splay{
splay *ch[2],*f;
int color_mark,rev_mark;
int my_color;
int left_color,right_color,color_size;
inline void pushup(){
left_color=ch[0]->color_size?ch[0]->left_color:my_color;
right_color=ch[1]->color_size?ch[1]->right_color:my_color;
color_size=1;
if(ch[0]->color_size){
color_size+=ch[0]->color_size;
if(ch[0]->right_color==my_color)--color_size;
}
if(ch[1]->color_size){
color_size+=ch[1]->color_size;
if(ch[1]->left_color==my_color)--color_size;
}
}
inline void mark_rev(){
rev_mark^=1;
std::swap(ch[0],ch[1]);
std::swap(left_color,right_color);
}
inline void mark_color(int color){
my_color=color;
left_color=right_color=color;
color_size=color_size?1:0;
color_mark=color;
}
inline void pushdown(){
if(rev_mark){
ch[0]->mark_rev();
ch[1]->mark_rev();
rev_mark=0;
}
if(color_mark){
ch[0]->mark_color(color_mark);
ch[1]->mark_color(color_mark);
color_mark=0;
}
}
}*null,node[N];
int cnt_color;
inline int isroot(splay *p){
return p->f->ch[0]!=p&&p->f->ch[1]!=p;
}
inline int get(splay *p){
return p->f->ch[1]==p;
}
inline void dig(splay *p){
if(isroot(p)){
p->pushdown();
return;
}
dig(p->f);
p->pushdown();
}
inline void rotate(splay *p){
splay *fa=p->f,*pa=fa->f;
int j=get(p);
if(!isroot(fa))pa->ch[get(fa)]=p;
if((fa->ch[j]=p->ch[j^1])!=null)fa->ch[j]->f=fa;
fa->f=p,p->ch[j^1]=fa,p->f=pa;
fa->pushup();
p->pushup();
}
inline void spaly(splay *p){
dig(p);
for(splay *fa=p->f;!isroot(p);rotate(p),fa=p->f)
if(!isroot(fa))
rotate(get(fa)==get(p)?fa:p);
}
inline void expose(splay *x){
splay *y=null;
while(x!=null){
spaly(x);
x->ch[1]=y;
x->pushup();
y=x;
x=x->f;
}
}
inline void make_root(splay *p,int color){
expose(p),spaly(p),p->mark_rev(),p->mark_color(color);
}
inline void dfs(int x,int fa){
node[x].f=node+fa;
node[x].ch[0]=node[x].ch[1]=null;
node[x].my_color=node[x].left_color=node[x].right_color=++cnt_color;
node[x].color_size=1;
if(c[i].to!=fa)
dfs(c[i].to,x);
}
inline void Init(){
null=node;
null->ch[0]=null->ch[1]=null->f=null;
dfs(1,0);
}
inline void Main(){
Init();
register int i,x;
splay *p;
for(i=1;i<=m;++i){
p=node+poi[i];
switch(opt[i]){
case 1:
expose(p),spaly(p);
p->mark_color(++cnt_color);
break;
case 2:
make_root(p,++cnt_color);
break;
case 3:
expose(p),spaly(p);
ans3[i]=p->color_size-1;
break;
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
int i,x,y;
for(i=1;i<n;++i){
scanf("%d%d",&x,&y);
}
for(i=1;i<=m;++i){
scanf("%s",s);
switch(s[2]){
case 'L':opt[i]=1;break;
case 'C':opt[i]=2;break;
case 'Q':opt[i]=3;break;
}
scanf("%d",&poi[i]);
}
work1::Main(),work2::Main();
for(i=1;i<=m;++i)
if(opt[i]==3){
printf("%.10f\n",(double)ans1[i]/ans2[i]+ans3[i]);
}
return 0;
}
Kod

UOJ Round #17

T1,对着部分分码了一发贪心,结果过了所有样例,出题人在逗我?不管了,就这样吧.
T2,额,啥玩意,暴力怎么打,为什么会出现不在点上的情况……
T3,想了好久,仍然只会10分……

T1的贪心是错的,给一个样例:
5
11 12 13 15 19

#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS=xB,*xT=xB;
register char ch=gtc;
for(x=0;ch<'0'||ch>'9';ch=gtc);
for(;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=gtc);
}
typedef long long LL;
const int A=18;
const LL Inf=1e16;
const int N=100010;
const int F=(1<<18)+10;
int bin[A],pub,all;
int n,a[N],m,st[F],ex[F];
LL ans,f[F];
int main(){
register int i,j,s;
for(i=1;i<=n;++i)
ans=(LL)pub*n;
bin[0]=1;
for(i=1;i<A;++i)bin[i]=bin[i-1]<<1;
ex[0]=1;
all^=pub;
for(i=1;i<=n;++i)
ex[(a[i]&all)^all]=1;
for(i=all;i;i=(i-1)&all){
if(ex[i])continue;
for(j=0;j<A;++j)
if((all&bin[j])&&(i&bin[j])==0)
ex[i]|=ex[i|bin[j]];
}
for(i=all;i;i=(i-1)&all)
st[++m]=i;
f[0]=0;
for(i=m;i>0;--i){
s=st[i],f[s]=Inf;
for(j=s;j;j=(j-1)&s){
if(f[s]<=(s^j))break;
if(ex[j])f[s]=std::min(f[s],f[s^j]+(s^j));
}
}
ans+=f[all];
printf("%lld\n",ans);
return 0;
}
Kod

T2,就是仔细分析一下题目中描述的运动,设计合理的状态,然后二分+bfs或者直接spfa来解决它,而分析这个运动以及设计合理状态,就是这道题的关键所在了,这也需要一定的证明正确性,以及意识到错误的能力.我在分析题目和设计状态的方面还是比较弱的.

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ft first
#define sd second
#define mmp(a,b) (std::make_pair(a,b))
typedef long long LL;
typedef std::pair<int,int> pii;
const int N=1010;
const double Inf=1e7;
const double eps=1e-6;
double dis[N][N],Dis[N][N];
bool fin[N][N];
struct V{
int to,next,id;
}c[N<<1];
inline void add(int x,int y,int z){
}
int n,sx,sy;
int a[N],b[N];
int degree[N];
pii queue[N*N],e[N];
int front,back;
bool in[N][N];
inline double query(int i,int x,int y){
double ret=std::min(dis[i][x],dis[i][y]);
double tx,ty,ki,bi,kei,bei;
if(b[x]==b[y])tx=a[i],ty=b[x];
else if(a[x]==a[y])tx=a[x],ty=b[i];
else{
ki=(double)(a[y]-a[x])/(b[x]-b[y]);
bi=b[i]-a[i]*ki;
kei=(double)(b[x]-b[y])/(a[x]-a[y]);
bei=b[x]-a[x]*kei;
tx=(bi-bei)/(kei-ki);
ty=tx*ki+bi;
}
if((a[x]<=tx&&tx<=a[y])||(a[y]<=tx&&tx<=a[x]))
ret=std::sqrt((tx-a[i])*(tx-a[i])+(ty-b[i])*(ty-b[i]));
return ret;
}
inline bool check(int x,int y,double lim){
return (fin[x][e[y].ft]&&dis[x][e[y].ft]<=lim)||(fin[x][e[y].sd]&&dis[x][e[y].sd]<=lim);
}
inline bool check(double lim){
front=back=0;
memset(in,0,sizeof(in));
register int x,y,i,u,w,q;
if(Dis[sy][c[i].id]<=lim){
in[sy][c[i].id]=true;
queue[back++]=mmp(sy,c[i].id);
}
if(Dis[sx][c[i].id]<=lim){
in[sx][c[i].id]=true;
queue[back++]=mmp(sx,c[i].id);
}
while(front!=back){
x=queue[front].ft,y=queue[front].sd;
front++;
w=e[y].ft,q=e[y].sd;
u=c[i].to;
if(in[u][y]==false&&Dis[u][y]<=lim){
if(check(u,y,lim))return true;
in[u][y]=true;
queue[back++]=mmp(u,y);
}
u=c[i].id;
if(in[w][u]==false&&Dis[w][u]<=lim){
if(check(w,u,lim))return true;
in[w][u]=true;
queue[back++]=mmp(w,u);
}
if(in[q][u]==false&&Dis[q][u]<=lim){
if(check(q,u,lim))return true;
in[q][u]=true;
queue[back++]=mmp(q,u);
}
}
}
return false;
}
inline double judge(){
double l=dis[sx][sy],r=Inf,mid;
while(l+eps<r){
mid=(l+r)*0.5;
if(check(mid))r=mid;
else l=mid;
}
return r;
}
int main(){
//freopen("rio.in","r",stdin);
scanf("%d%d%d",&n,&sx,&sy);
register int i,j,x,y;
for(i=1;i<=n;++i)
scanf("%d%d",&a[i],&b[i]);
for(i=1;i<n;++i){
scanf("%d%d",&x,&y);
++degree[x],++degree[y];
e[i]=mmp(x,y);
}
for(i=1;i<=n;++i)
for(j=1;j<=n;++j){
dis[i][j]=std::sqrt((LL)(a[i]-a[j])*(LL)(a[i]-a[j])+(LL)(b[i]-b[j])*(LL)(b[i]-b[j]));
fin[i][j]=(degree[i]==1&&degree[j]==1)||(i==j);
}
if(sx==sy){puts("0");return 0;}
if(fin[sx][sy]){
printf("%.10f\n",dis[sx][sy]);
return 0;
}
for(i=1;i<=n;++i)
for(j=1;j<n;++j)
Dis[i][j]=query(i,e[j].ft,e[j].sd);
printf("%.10f\n",judge());
return 0;
}
Kod

T3,还没有去搞正解,只能说知道这题在问啥吧.正解是积分,我的积分还是很弱,在这道题里,除了打了一个傻暴力以外,最大的收获就是学了一发神奇的随机化.学到的地方大概是:多次随机去计算期望值,枚举分数来匹配小数从而解决答案在模意义下的问题,调整精度来调整随机化结果,一个神奇的随机数写法.

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
namespace RAND{
int seed=45,put_out=0x7fffffff;
inline double rando(){
seed^=seed<<5;
seed^=seed>>17;
seed^=seed<<13;
return (double)(seed&=put_out)/put_out;
}
}
typedef long long LL;
const int N=30;
const int P=998244353;
const int T=10000000;
const int L=100;
const double eps=1e-5;
int n,m,a[N*N],b[N*N],inv[L+10];
double f[N];
int main(){
register int i,j;
inv[1]=1;
for(i=2;i<=L;++i)inv[i]=(-(LL)P/i*inv[P%i]%P+P)%P;
if(n>10){
printf("%lld\n",(LL)(3*n-2)*inv[2*n]%P);
return 0;
}
for(i=1;i<=m;++i)
register double sum=0.,max;
for(i=1;i<=T;++i){
max=0.;
for(j=1;j<=n;++j)f[j]=RAND::rando(),max=std::max(max,f[j]);
for(j=1;j<=m;++j)max=std::max(max,f[a[j]]+f[b[j]]);
sum+=max;
}
sum/=T;
double min=1e16;
int ans;
for(i=1;i<=(L<<1);++i){
for(j=1;j<=L;++j)
if(std::fabs((double)i/j-sum)<min){
min=std::fabs((double)i/j-sum);
ans=(LL)i*inv[j]%P;
if(min<eps)break;
}
if(min<eps)break;
}
printf("%d\n",ans);
return 0;
}
Kod

No.18省选模拟赛

T1,我感觉我要是当时早点从这深渊中脱离,去打一个状压,兴许还能是一个O(n^2)dp,就能多拿一些分数,而且还会剩下很多时间,切题上瘾的毛病最近又犯了,合理分配时间,尽量拿高分才是重中之重啊!

T2,我的做法由于HZOI上没有包而拿到了80分……然而,实际上,有两种特殊情况我没有判,少拿了8分,还是思维不严谨……这道题的栈空间好像还有点迷……

T3,无论如何都不要放弃梦想……

math模拟赛

T1,我那个差11s没交上的暴力可以多拿10分……

100分的话,继续沿用50分的思路,把点分成若干联通块.这次我们肯定不能像之前那样枚举权值,我们这次以最高位上是否有1,把点分为两部分,这两部分点一定内部联通,之间有一条最小的边(证明同50分做法).那么我们就会得到一种状态f,一种转移,但是我们发现我们转移的时候出现了一些奇奇怪怪的东西,g,求g的话,就不像f那样好求了,我们需要一些设计dp状态与转移的技巧,我们可以设计后缀意义的dp状态,并且用后缀方案数累加得到总和,这就有了g的转移,以及p的出现,而p的出现,可以沿用我们一开始的思路进行转移.这样这道题就结束了,只是还有一些dp转移的时候的一些小细节,以及,有一个必要的对于p的剪枝,具体细节见Kod.

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=55;
const int M=10;
const int FL=260;
const int P=258280327;
inline int Pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=(LL)ret*x%P;
x=(LL)x*x%P,y>>=1;
}
return ret;
}
int f[N][M],g[N][N][M],h[N][N][M][FL],bin[N*N],c[N][N],cnm[N][N][N][N];
inline void Init(){
int i,j,k,l;
bin[0]=1;
for(i=1;i<N*N;++i)
bin[i]=(bin[i-1]<<1)%P;
c[0][0]=1;
for(i=1;i<N;++i){
c[i][0]=1;
for(j=1;j<=i;++j)
c[i][j]=(c[i-1][j-1]+c[i-1][j])%P;
}
for(i=1;i<N;++i)
for(j=0;j<=i;++j)
for(l=1;l<N;++l)
for(k=0;k<=l;++k)
cnm[i][j][l][k]=(LL)c[i][j]*c[l][k]%P;
memset(f,-1,sizeof(f));
memset(g,-1,sizeof(g));
memset(h,-1,sizeof(h));
for(i=0;i<M;++i)
f[0][i]=f[1][i]=0;
for(i=2;i<N;++i)
f[i][0]=0;
for(i=0;i<N;++i)
for(j=0;j<N;++j){
g[i][j][0]=0;
for(k=1;k<FL;++k)
h[i][j][0][k]=0;
}
for(i=0;i<N;++i)
for(j=0;j<M;++j)
g[i][0][j]=g[0][i][j]=0;
for(i=0;i<M;++i)
for(j=0;j<FL;++j)
if(bin[i]-1<j)
for(l=0;l<N;++l)
for(k=0;k<N;++k)
h[l][k][i][j]=0;
}
inline int H(int s,int t,int m,int k){
if(h[s][t][m][k]!=-1)return h[s][t][m][k];
int i,j;LL ret=0;
for(i=0;i<=s;++i){
for(j=0;j<=t;++j){
ret+=
(i==0&&j==t)||(i==s&&j==0)?
(bin[m-1]>=k?bin[(s+t)*(m-1)]:H(s,t,m-1,k-bin[m-1])):
(LL)cnm[s][i][t][j]*((i!=0&&j!=0)?H(i,j,m-1,k):bin[(i+j)*(m-1)])%P*((i!=s&&j!=t)?H(s-i,t-j,m-1,k):bin[(s-i+t-j)*(m-1)]);
}
ret%=P;
}
return h[t][s][m][k]=h[s][t][m][k]=ret;
}
inline int G(int s,int t,int m){
if(g[s][t][m]!=-1)return g[s][t][m];
int i,ret=0,full=bin[m]-1;
for(i=1;i<=full;++i)
ret=(ret+H(s,t,m,i))%P;
return g[t][s][m]=g[s][t][m]=ret;
}
inline int F(int n,int m){
if(f[n][m]!=-1)return f[n][m];
int i,ret=0;
for(i=0;i<=n;++i)
ret=(ret+(LL)c[n][i]*((LL)F(i,m-1)*bin[(m-1)*(n-i)]%P+(LL)F(n-i,m-1)*bin[(m-1)*i]%P+G(i,n-i,m-1)+(i==0||i==n?0:bin[(n+1)*(m-1)])))%P;
return f[n][m]=ret;
}
int main(){
Init();
int n,m;
scanf("%d%d",&n,&m);
printf("%lld\n",(LL)F(n,m)*Pow(bin[n*m],P-2)%P);
return 0;
}
Kod

T2,我想得偏了,那个1e10的数据范围,挺杜教筛的嘛.

#include <map>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=10000000;
const int P=258280327;
const int inv2=129140164;
const int inv9=229582513;
std::map<LL,int> gg;
char mu[N+10];
int prime[N/10],len,g[N+10];
bool isnot[N+10];
int n;
inline LL Pow(LL x,LL y){
LL ret=1;
while(y){
if(y&1)ret=ret*x%P;
x=x*x%P,y>>=1;
}
return ret;
}
inline int G(LL n){
if(n<=N)return g[n];
if(gg.count(n))return gg[n];
LL ret=0,i,last;
for(i=2;i<=n;i=last+1){
last=n/(n/i);
ret=(ret+((i+last)%P)*((last-i+1)%P)%P*inv2%P*G(n/i))%P;
}
ret=(1-ret)%P;
return gg[n]=ret;
}
inline void Init(){
isnot[1]=true,mu[1]=1;
register int i,j;
for(i=2;i<=N;++i){
if(!isnot[i])prime[++len]=i,mu[i]=-1;
for(j=1;prime[j]*i<=N;++j){
isnot[prime[j]*i]=true;
if(i%prime[j]==0){
mu[prime[j]*i]=0;
break;
}
mu[prime[j]*i]=-mu[i];
}
}
for(i=1;i<=N;++i)
g[i]=(g[i-1]+i*mu[i])%P;
}
inline LL sum(LL n){
return (n%P*Pow(10,n)%P-(Pow(10,n)-1)*inv9%P)*inv9%P*10%P;
}
inline LL calc(LL n){
LL ret=0,i,last;
for(i=1;i<=n;i=last+1){
last=n/(n/i);
ret=(ret+(LL)(G(last)-G(i-1))*sum(n/i))%P;
}
return (ret+P)%P;
}
int main(){
Init();
LL n;
scanf("%lld",&n);
printf("%lld\n",calc(n));
return 0;
}
Kod

T3,看错了数据范围……106看成10^6,不过给106这种数据范围的,就是想让人看错的吧,以后注意一下,不过看到106的话,我更愿意相信他打错了.

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
typedef long long LL;
const int N=1000000;
int prime[N+10],len,min[N+10],mini[N+10];
int mi[N*10],*begin[N+10],size[N+10];
bool isnot[N+10];
int n,P,x,y;
struct Prime{
Prime *ch[2],*f;
int key,id;
inline void pushup(){
key=(LL)begin[id][size[id]]*ch[0]->key%P*ch[1]->key%P;
}
inline void* operator new(size_t);
}*null,*root,node[N+10];
inline void build(Prime *&p,int id,Prime *fa){
if(id>len){
p=null;
return;
}
p=node+id;
p->f=fa;
p->id=id;
build(p->ch[0],id<<1,p);
build(p->ch[1],(id<<1)|1,p);
p->pushup();
}
inline int quy(int x,int n){
register int ret=0,now=1;
while((LL)now*x<=n)++ret,now*=x;
return ret;
}
inline void Iput(int x){
while(min[x])
++size[min[x]],x/=prime[min[x]];
}
inline void update(Prime *p){
while(p!=null){
p->pushup();
p=p->f;
}
}
inline void get(int x,int opt){
register int ti;
while(min[x]){
ti=mini[x];
size[min[x]]+=opt*ti;
update(node+min[x]);
while(ti--)
x/=prime[min[x]];
}
}
inline void Init1(){
isnot[1]=true;
min[1]=0,mini[1]=0;
register int i,j;
for(i=2;i<=N;++i){
if(!isnot[i])prime[++len]=i,min[i]=len,mini[i]=1;
for(j=1;prime[j]*i<=N;++j){
isnot[prime[j]*i]=true;
min[prime[j]*i]=j;
mini[prime[j]*i]=1;
if(i%prime[j]==0){
mini[prime[j]*i]+=mini[i];
break;
}
}
}
null=node;
null->ch[0]=null->ch[1]=null;
null->f=null;
null->id=0;
null->key=1;
}
inline void Init2(){
scanf("%d%d%d%d",&n,&P,&x,&y);
x=std::abs(x);
y=std::abs(y);
if(n-y-x<0){
puts("0");
exit(0);
}
if((x&1)!=((n+y)&1)){
puts("0");
exit(0);
}
register int i,j,pos=0,lim;
for(i=1;i<=n;++i)Iput(i);
for(i=1;i<=len;++i){
++pos;
begin[i]=mi+pos;
mi[pos]=1;
lim=size[i]+quy(prime[i],n)*2;
for(j=1;j<=lim;++j)
mi[pos+1]=(LL)mi[pos]*prime[i]%P,++pos;
}
build(root,1,null);
}
inline void Work(){
register int i,ans=0,a,b,c,d;
a=0,b=x,c=(n-y-x)>>1,d=(n+y-x)>>1;
for(i=1;i<=a;++i)get(i,-1);
for(i=1;i<=b;++i)get(i,-1);
for(i=1;i<=c;++i)get(i,-1);
for(i=1;i<=d;++i)get(i,-1);
ans=root->key;
while(c&&d){
get(c,1),get(d,1);
--c,--d;
++a,++b;
get(a,-1),get(b,-1);
ans=(ans+root->key)%P;
}
printf("%d\n",ans);
}
int main(){
//freopen("test.in","r",stdin);
//freopen("need.out","w",stdout);
//freopen("rio.in","r",stdin);
Init1();
Init2();
Work();
return 0;
}
Kod

#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=1000010;
int n,x,y,mod,P,p,phi,fac[N],num;
inline int Pow(int x,int y){
int ret=1;
while(y){
if(y&1)ret=(LL)ret*x%P;
x=(LL)x*x%P,y>>=1;
}
return ret;
}
inline int cnt(int n){
return n?n/p+cnt(n/p):0;
}
inline int sum(int n){
return n?((LL)(n/P?Pow(fac[P],n/P):1)*fac[n%P]%P*sum(n/p)%P):1;
}
#define deal(n,a,b) int a=sum(n),b=cnt(n);
inline int C(int n,int m){
if(m>n)return 0;
deal(n,a0,b0)
deal(m,a1,b1)
deal(n-m,a2,b2)
b0-=b1+b2;
if(b0>=num)return 0;
return (LL)a0*Pow(a1,phi-1)%P*Pow(a2,phi-1)%P*Pow(p,b0)%P;
}
inline int calc(){
int ret=0,i,a,b,c,d;
fac[0]=1;
for(i=1;i<=P&&i<=n;++i)
fac[i]=(i%p)?(LL)fac[i-1]*i%P:fac[i-1];
a=0,b=x,c=(n-y-x)>>1,d=(n+y-x)>>1;
while(c>=0){
ret=(ret+(LL)C(n,a+b)*C(a+b,a)%P*C(c+d,c)%P)%P;
++a,++b,--c,--d;
}
return ret;
}
int main(){
scanf("%d%d%d%d",&n,&mod,&x,&y);
x=std::abs(x),y=std::abs(y);
if(n-y-x<0||((x&1)!=((n+y)&1))){
puts("0");
return 0;
}
int i,s=mod,ans=0;
for(i=2;s>1;++i){
if(i*i>s)i=s;
if(s%i==0){
p=i,P=1,num=0;
while(s%p==0)
++num,P*=p,s/=p;
phi=P/p*(p-1);
ans=(ans+(LL)calc()*(mod/P)%mod*Pow(mod/P,phi-1))%mod;
}
}
printf("%d\n",ans);
return 0;
}
Kod

No.21省选模拟赛

T1.啊……以后考试一定不要困了啊,虽然题目描述有误,但是,我明明想到了正解,却因为困,而选择了错误的策略……

#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS,*xT;
register char ch=gtc();bool ud=false;
for(x=0;ch<'0'||ch>'9';ch=gtc())if(ch=='-')ud=true;
for(;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=gtc());
if(ud)x=-x;
}
const int N=4010;
const int M=200010;
const int oo=0x7fffffff;
struct V{
int to,next,f;
}c[M<<3];
inline void add(int x,int y,int z){
}
int n,m,e1[M],e2[M],w1[M],w2[N],S,T;
int deep[M+N],queue[M<<1],front,back;
#define poi(a) (a)
#define edge(a) ((a)+n)
inline void Init(){
int i;
for(i=1;i<=n;++i)
for(i=1;i<=m;++i)
S=n+m+1,T=n+m+2;
}
inline bool bfs(){
memset(deep,-1,sizeof(deep));
front=back=0;
queue[back++]=S;
deep[S]=0;
int x,i;
while(front!=back){
x=queue[front++];
if(c[i].f&&deep[c[i].to]==-1){
deep[c[i].to]=deep[x]+1;
if(c[i].to==T)return true;
queue[back++]=c[i].to;
}
}
return false;
}
inline int dfs(int x,int v){
if(x==T||v==0)return v;
int ret=0,f;
if(c[i].f&&deep[c[i].to]==deep[x]+1){
f=dfs(c[i].to,std::min(v,c[i].f));
v-=f,ret+=f,c[i].f-=f,c[i^1].f+=f;
if(!v)break;
}
if(!ret)deep[x]=-1;
return ret;
}
inline bool check(int x){
int ret=0;
t=1;
int i;
for(i=1;i<=m;++i){
ret+=w1[i];
}
for(i=1;i<=n;++i)
while(bfs())ret-=dfs(S,oo);
return ret>0;
}
inline void Print(){
int l=0,r=10000,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d\n",ans);
}
int main(){
Init(),Print();
return 0;
}
n+m点、n+m边、100分
#include <cstdio>
#include <cstring>
#include <algorithm>
char xB[(1<<15)+10],*xS,*xT;
register char ch=gtc();bool ud=false;
for(x=0;ch<'0'||ch>'9';ch=gtc())if(ch=='-')ud=true;
for(;ch>='0'&&ch<='9';x=x*10+ch-'0',ch=gtc());
if(ud)x=-x;
}
const int N=4010;
const int M=200010;
const int oo=0x7fffffff;
struct V{
int to,next,f;
}c[(M+(N<<1))<<1];
inline void add(int x,int y,int z1,int z2){
}
int n,m,e1[M],e2[M],w1[M],w2[N],S,T,w3[N];
int deep[N],queue[N],front,back;
inline void Init(){
int i;
for(i=1;i<=n;++i){
w2[i]<<=1;
}
for(i=1;i<=m;++i){
w3[e1[i]]+=w1[i],w3[e2[i]]+=w1[i];
}
S=n+1,T=n+2;
}
inline bool bfs(){
memset(deep,-1,sizeof(deep));
front=back=0;
queue[back++]=S;
deep[S]=0;
int x,i;
while(front!=back){
x=queue[front++];
if(c[i].f&&deep[c[i].to]==-1){
deep[c[i].to]=deep[x]+1;
if(c[i].to==T)return true;
queue[back++]=c[i].to;
}
}
return false;
}
inline int dfs(int x,int v){
if(x==T||v==0)return v;
int ret=0,f;
if(c[i].f&&deep[c[i].to]==deep[x]+1){
f=dfs(c[i].to,std::min(v,c[i].f));
v-=f,ret+=f,c[i].f-=f,c[i^1].f+=f;
if(!v)break;
}
if(!ret)deep[x]=-1;
return ret;
}
inline bool check(int x){
int ret=0,i;
for(i=1;i<=m;++i){
ret+=w1[i]<<1;
}
for(i=1;i<=n;++i){
}
while(bfs())ret-=dfs(S,oo);
return ret>0;
}
inline void Print(){
int l=0,r=5000,mid,ans=0;
while(l<=r){
mid=(l+r)>>1;
if(check(mid))
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%d\n",ans);
}
int main(){
//freopen("rio.txt","r",stdin);
Init(),Print();
return 0;
}
n点、n+m边、100分

T2,我考试的代码的正确性是有的,只不过有一个小细节,没有判到(思维还是不严谨啊,同时考试的时候一定要确保自己的冷静沉着),但是那对我炸掉的精度来说,已经无关紧要了.

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=55;
const double oo=1e15;
#define yy(a,b) (std::fabs((a)-(b))<1e-9)
int n;
struct Poi{
double x,y,z;
scanf("%lf%lf%lf",&x,&y,&z);
}
};
inline double disf(Poi a,Poi b){
return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z);
}
inline double dis(Poi a,Poi b){
return std::sqrt(disf(a,b));
}
struct Line{
Poi s,t;
}
}me;
inline double dis(Line a,Poi b){
double x=dis(a.s,b);
double y=dis(a.t,b);
double z=dis(a.s,a.t);
if(yy(x+y,z)||yy(x+z,y)||yy(y+z,x))return 0;
double cos_k=(x*x+y*y-z*z)/(2*x*y);
double sin_k=std::sqrt(1-cos_k*cos_k);
double s=x*y*sin_k;
return s/z;
}
struct Cir{
Poi h;
double r;
}
}cir[N];
inline double dis(Cir a,Line b){
double dis1=dis(b,a.h);
if(dis1>a.r)return oo;
double dis2=std::sqrt(a.r*a.r-dis1*dis1);
double dis3=std::sqrt(disf(a.h,b.s)-dis1*dis1);
double dis4=std::sqrt(disf(a.h,b.t)-dis1*dis1);
double dis5=dis(b.s,b.t);
if(yy(dis3+dis4,dis5))return dis3-dis2;
if(dis3<dis4)return oo;
return dis3-dis2;
}
inline Poi go(Line a,double b){
double dis1=dis(a.s,a.t);
double k=b/dis1;
Poi ret;
ret.x=(a.t.x-a.s.x)*k+a.s.x;
ret.y=(a.t.y-a.s.y)*k+a.s.y;
ret.z=(a.t.z-a.s.z)*k+a.s.z;
return ret;
}
inline Poi dc(Poi a,Poi b){
Poi ret;
ret.x=2*b.x-a.x;
ret.y=2*b.y-a.y;
ret.z=2*b.z-a.z;
return ret;
}
inline Poi dc(Poi a,Line b){
double dis1=dis(b,a);
double dis2=dis(a,b.s);
double dis3=dis(a,b.t);
double dis4=std::sqrt(dis2*dis2-dis1*dis1);
double dis5=std::sqrt(dis3*dis3-dis1*dis1);
double dis6=dis(b.s,b.t);
Poi mid=go(b,dis4*(yy(dis4+dis5,dis6)||dis3<dis2?1:-1));
return dc(a,mid);
}
inline Poi dc(Poi a,Poi b,Poi c){
return dc(a,(Line){b,c});
}
inline Line Pia(Line a,Cir b){
Poi aha=go(a,dis(b,a));
Poi ehe=dc(a.s,aha,b.h);
return (Line){aha,ehe};
}
inline void Init(){
scanf("%d",&n);
int i;
for(i=1;i<=n;++i)
}
inline int Pang(int last){
int i,id=-1;
double min=oo,tmp;
for(i=1;i<=n;++i){
if(i==last)continue;
tmp=dis(cir[i],me);
if(tmp<min){
min=tmp;
id=i;
}
}
return id;
}
inline void Work(){
int i,next=0;
for(i=1;i<=11;++i){
next=Pang(next);
if(next==-1)return;
if(i==11){
printf("etc.");
return;
}
printf("%d ",next);
me=Pia(me,cir[next]);
}
}
int main(){
//freopen("rio.txt","r",stdin);
Init(),Work();
return 0;
}

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define pf(a) ((a)*(a))
const int N=55;
const double oo=1e15;
int n;
struct Poi{
double x,y,z;
inline friend Poi operator -(Poi a,Poi b){
return (Poi){a.x-b.x,a.y-b.y,a.z-b.z};
}
scanf("%lf%lf%lf",&x,&y,&z);
}
};
struct Line{
Poi s,t;
t=t-s;
}
}me;
struct Cir{
Poi h;
double r;
}
}cir[N];
inline double dis(Cir a,Line b){
double x=b.s.x-a.h.x;
double y=b.s.y-a.h.y;
double z=b.s.z-a.h.z;
double A=pf(b.t.x)+pf(b.t.y)+pf(b.t.z);
double B=2*b.t.x*x+2*b.t.y*y+2*b.t.z*z;
double C=x*x+y*y+z*z-a.r*a.r;
double det=B*B-4*A*C;
if(det<0)return oo;
double k=(-B-std::sqrt(det))/(2*A);
if(k<0)return oo;
return std::sqrt(pf(k*b.t.x)+pf(k*b.t.y)+pf(k*b.t.z));
}
inline Poi go(Line a,double b){
double k=b/std::sqrt(pf(a.t.x)+pf(a.t.y)+pf(a.t.z));
Poi ret;
ret.x=a.t.x*k+a.s.x;
ret.y=a.t.y*k+a.s.y;
ret.z=a.t.z*k+a.s.z;
return ret;
}
inline Line Pia(Line a,Cir b){
Poi aha=go(a,dis(b,a));
Poi o=a.s-aha;
Poi m=aha-b.h;
Poi t;
double k=(2*m.x*o.x+2*m.y*o.y+2*m.z*o.z)/(m.x*m.x+m.y*m.y+m.z*m.z);
t.x=k*m.x-o.x;
t.y=k*m.y-o.y;
t.z=k*m.z-o.z;
return (Line){aha,t};
}
inline void Init(){
scanf("%d",&n);
int i;
for(i=1;i<=n;++i)
}
inline int Pang(int last){
int i,id=-1;
double min=oo,tmp;
for(i=1;i<=n;++i){
if(i==last)continue;
tmp=dis(cir[i],me);
if(tmp<min){
min=tmp;
id=i;
}
}
return id;
}
inline void Work(){
int i,next=0;
for(i=1;i<=11;++i){
next=Pang(next);
if(next==-1)return;
if(i==11){
printf("etc.");
return;
}
printf("%d ",next);
me=Pia(me,cir[next]);
}
}
int main(){
Init(),Work();
return 0;
}

T3,考试的时候给这题时间少了,还有就是我的数学能力不强.

100分的话,就是40分状压加按根号分类处理.

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
typedef long long LL;
const int N=3000;
int prime[N+10],min[N+10],len,size[N+10];
bool isnot[N+10];
int n,lit[N+10],big[N+10],lm,bm,now,last,could[(1<<13)+10];
LL ans,f[2][(1<<13)+10];
inline void Iput(int x){
while(min[x])
++size[min[x]],x/=prime[min[x]];
}
inline void Init(){
isnot[1]=true;
min[1]=0;
register int i,j;
for(i=2;i<=N;++i){
if(!isnot[i])prime[++len]=i,min[i]=len;
for(j=1;prime[j]*i<=N;++j){
isnot[prime[j]*i]=true;
min[prime[j]*i]=j;
if(i%prime[j]==0)break;
}
}
}
inline void dp1(){
now=0,last=1;
f[0][0]=1;
int i,j,k,full,sum;
full=(1<<lm)-1;
for(i=0;i<=full;++i){
sum=1;
for(j=0;j<lm;++j)
if(i&(1<<j)){
sum*=lit[j+1];
if(sum>n){sum=-1;break;}
}
could[i]=sum;
}
for(i=1;i<=lm;++i){
full=(1<<(i-1))-1;
now^=1,last^=1;
memcpy(f[now],f[last],sizeof(f[now]));
for(j=0;j<=full;++j){
if(could[j|(1<<i-1)]!=-1)
for(k=full^j;;k=(k-1)&(full^j)){
f[now][(j|(1<<i-1))|k]+=f[last][k];
if(!k)break;
}
}
}
}
inline void dp2(){
int i,j,k,full=(1<<lm)-1;
for(i=1;i<=bm;++i){
now^=1,last^=1;
memset(f[now],0,sizeof(f[now]));
for(j=0;j<=full;++j){
if(could[j]!=-1&&could[j]*big[i]<=n)
for(k=full^j;;k=(k-1)&(full^j)){
f[now][j|k]+=f[last][k];
if(!k)break;
}
}
}
ans=f[now][full];
}
inline void Work(){
scanf("%d",&n);
int i,st=std::sqrt(n+0.5);
for(i=1;i<=n;++i)
Iput(i);
for(i=1;i<=len;++i){
if((size[i]&1)==0||size[i]==1)continue;
if(prime[i]<=st)lit[++lm]=prime[i];
else big[++bm]=prime[i];
}
dp1(),dp2();
printf("%lld\n",ans<<1);
}
int main(){
Init(),Work();
return 0;
}
Kod

No.22省选模拟赛

T1,题干简洁,应该是个反演,先把暴力码出来.码完去看T2,题干简洁,不是很会,先码出来一个12分暴力.然后去看T3,感觉从哪里见过,不管了,先码个暴力,不对啊,我的复杂度不对,又想了想,想出来一个小性质,然后开始码,码着码着突然意识到我tm打的是正解啊.打完T3,没调,又回到了T1,推了一下,推出来一个O(n^2ln(n^2))的做法,码了出来,测了一下极限数据,4s,完蛋.我先拿这玩意和暴力拍了一下,然后卡了卡常,卡到了2.1s,静态查了一波错,一看时间不对,感觉在这里查错时间太长了,而且太低效了.于是去调T3,我干,这玩意咋打暴力啊,造数据麻烦也就算了,tmd不会打暴力啊,YY了一会,不会,于是赶紧静态查错一波,去看T2了.T2,在原来12分的dfs基础之上,打了一个32分的状压.考试时间不多了,于是去手造小样例测试T3程序.

T1,我的做法正好卡过……正解是O(n^2lnn)的,写丑了和我的做法差不多……不过着这玩意出5000还真是有点卡……

O(n^2)预处理gcd用得还挺多,而且对于特殊模数利用自然溢出是可以卡常的.

T2,我只是想到了压每一位,但是没想到去换个角度搞,但是我感觉我当时确实有点不冷静,也有点困,还有点“踌躇满志”……

T3,是一道十分好想且好写的半平面交,只不过到现在我还是很不会写暴力.

zzh似乎被50分暴力套住,以为自己想到的是50分暴力,所以就把100分打成了50分.一开始我也以为自己的正解是50分暴力,后来打着打着才发现自己是正解,所以分析复杂度还是很重要的吧.

(这个是最后一篇,当时还没写完……写的时候在进行高密度考试所以和之前写得不一样……)

avoid:
困倦、慌乱、自满、犹豫不决、兴奋;
考试之外的事情带到考试上来;
为不必要的小事去找不值得的气;
盲目去冒一些不必要的险,比如在不确定的情况下使用不熟悉的知识点;
同样的错误重复出现;
exp:
路子不通,换路子;
不要放弃任何一道题,再看两眼就会有新的希望;
犹豫不决会把小的问题变大,会把小的疑惑放大,所以说遇事果决是不错的选择;
保持镇定,时刻冷静,是拿高分的基础;
想要翻盘,就不要想着自己在翻盘,要想着自己正在打一场新的比赛(这句话不只是说一试,同样也在说在一场考试中的前后期);
别人的节奏是别人的节奏,自己的路子是自己的路子,就算别人AK,跟我没关系,就算别人爆零,跟我也没关系;
多一些思考,多一线希望;
时间分配的均衡度与得分往往是正相关的;
码,要思路清晰,速战速决;
调,要保持冷静,速战速决;
想打对拍就不要拖延;
想验证程序,但是不会写暴力,或者不会造数据,就快手造小样例,并且加大眼动(脑动)查错力度;
没时间优化算法,可以,但是懒得去优化是绝对不可以的,尤其是你明知道你的程序慢,还不去优化;
不要觉得正解的时间复杂度一定不卡时限;
正确分析复杂度有时候会让你避免不必要的错误;
knowledge:
剪枝是dfs的重中之重;
最小割的Inf边,是网络流的巧妙;
No.22省选模拟赛:
O(n^2)预处理gcd可以用来减少复杂度;
维数递增地推广,不仅仅是递推可以用,一些数学规律,数学公式也可以尝试这样做;
遇到特殊模数,有时候可以用自然溢出卡常;
分析问题,转化问题,会方便你设计solution;
类似差分又类似容斥地减去无用状态,会方便dp;
积累反演式子:

posted @ 2018-03-11 09:03  TS_Hugh  阅读(...)  评论(... 编辑 收藏