SDOI2018
去ctsc和apio的时候就听山东妹子说SD round2的题一般不是很可做
这套题充分体现了Serene的sb程度无人可比
D1T1物理实验
一看就是计算几何题,对码力要求有点高,让我想起了SCOI我炸的那道计算几何题
感觉这个还没有SCOID2T2复杂?
反正现在还没码出来,准确来说是暂时不想码,码到一半,有时间再码完
D1T2战略游戏
看了一会,大概想到了什么点双,什么一个点双向其包含的点连边
竟然没发现这就是圆方树?
我真是如此智障……
圆方树,对于每个询问建虚树
我点双的板子又写错了,前几天还刚写过来着……为此调了一天,真是太sb了
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<set> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int maxn=4e5+7,maxt=23,W=19; int Td,n,m,Q,k,p[maxn]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int fir[maxn],nxt[2*maxn],to[2*maxn],e=1; void add(int x,int y) { to[++e]=y;nxt[e]=fir[x];fir[x]=e; to[++e]=x;nxt[e]=fir[y];fir[y]=e; } int FIR[maxn],NXT[2*maxn],TO[2*maxn],E=0; void ADD(int x,int y) { // printf("ADD:%d->%d\n",x,y); TO[++E]=y;NXT[E]=FIR[x];FIR[x]=E; TO[++E]=x;NXT[E]=FIR[y];FIR[y]=E; } int dfn[maxn],end[maxn],low[maxn],dfn_clock; int zz[maxn],top,toth; set<int> G; set<int>::iterator it; void tj(int pos) { dfn[pos]=low[pos]=++dfn_clock; int y,z,bot; for(y=fir[pos];y;y=nxt[y]) { if(dfn[z=to[y]]) {low[pos]=min(low[pos],dfn[z]);continue;} zz[++top]=y; bot=top; tj(z); low[pos]=min(low[pos],low[z]); zz[++top]=y^1; if(low[z]==dfn[pos]) { ++toth; G.clear(); For(i,bot,top) G.insert(to[zz[i]]); for(it=G.begin();it!=G.end();++it) ADD(n+toth,*it); top=bot-1; } } } int fa[maxn][maxt],sum[maxn][maxt],dep[maxn]; void dfs(int pos,int f) { fa[pos][0]=f; sum[pos][0]=pos<=n; dfn[pos]=++dfn_clock; dep[pos]=dep[f]+1; For(i,1,W) { fa[pos][i]=fa[fa[pos][i-1]][i-1]; sum[pos][i]=sum[pos][i-1]+sum[fa[pos][i-1]][i-1]; } int y,z; for(y=FIR[pos];y;y=NXT[y]) { if((z=TO[y])==f) continue; dfs(z,pos); } end[pos]=dfn_clock; } bool cmp(const int x,const int y) {return dfn[x]<dfn[y];} int get_lca(int x,int y) { if(dep[x]!=dep[y]) { if(dep[x]<dep[y]) swap(x,y); Rep(i,W,0) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; } if(x==y) return x; Rep(i,W,0) if(fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } int get_sum(int x,int l) { int rs=0; Rep(i,W,0) if(l>=(1<<i)) { l-=(1<<i); rs+=sum[x][i]; x=fa[x][i]; } return rs; } int get_ans() { int t=k,x,rs=-k; sort(p+1,p+k+1,cmp); For(i,1,k-1) { x=get_lca(p[i],p[i+1]); if(x!=p[i]) p[++t]=x; } k=t; t=0; sort(p+1,p+k+1); k=unique(p+1,p+k+1)-(p+1); sort(p+1,p+k+1,cmp); zz[++t]=p[1];rs+=sum[p[1]][0]; For(i,2,k) { x=p[i]; while(dfn[x]<dfn[zz[t]]||dfn[x]>end[zz[t]]) t--; rs+=get_sum(x,dep[x]-dep[zz[t]]); zz[++t]=x; } return rs; } void clear() { For(i,1,n+toth) fir[i]=FIR[i]=dfn[i]=0; E=dfn_clock=top=toth=0; e=1; } int main() { read(Td); int x,y; while(Td--) { clear(); read(n); read(m); For(i,1,m) { read(x); read(y); add(x,y); } tj(1); dfn_clock=0; dfs(1,0); read(Q); For(i,1,Q) { read(k); For(j,1,k) read(p[j]); printf("%d\n",get_ans()); } } return 0; }
附上rand:
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<ctime> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const int Td=3,N=5,M=5,Q=3,K=5; int n,m,q,k,p[N+7]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } int main() { srand((unsigned)time(NULL)); printf("%d\n",Td); int x,y; For(cs,1,Td) { n=rand()%N+3; m=rand()%M+n-1; printf("%d %d\n",n,m); For(i,1,n) p[i]=i; random_shuffle(p+1,p+n+1); For(i,2,n) printf("%d %d\n",p[rand()%(i-1)+1],p[i]); For(i,n,m) { x=y=rand()%n+1; while(x==y) y=rand()%n+1; printf("%d %d\n",x,y); } q=rand()%Q+2; printf("%d\n",q); For(i,1,q) { k=rand()%min(K,n-1)+2; printf("%d",k); random_shuffle(p+1,p+n+1); For(j,1,k) printf(" %d",p[j]); printf("\n"); } } return 0; }
D1T3 反回文串
我一直在想啥子容斥啊,啥子那样的串可能是
1、一个回文串
2、两个偶回文串
3、一个偶回文串+一个奇回文串
大方向都错了,怪不得百思不得其解
一看数据范围就是推式子题,而根据循环节长度来做多有趣的,可以用到sigma把式子列出来。
而我tm是在找规律么,式子都列不出来
感觉这样的题,我考场上永远想不出正解来……
听说要卡log的快速乘,但是我并没有被卡啊,感觉还是蛮快的?
题解:https://www.luogu.org/problemnew/show/P4607
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> #include<set> using namespace std; #define ll long long #define db long double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const db eps=1e-8; const int TM=20,M=120,maxn=23; ll Td,n,K,mod,p[maxn],sum[maxn],tot; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } ll gcd(ll x,ll y) {return y==0? x:gcd(y,x%y);} ll qp(ll x,ll k) { ll rs=1; x%=mod; while(k) { if(k&1) rs=rs*x%mod; k>>=1; x=x*x%mod; } return rs; } ll qc(ll x,ll k,ll mod) { ll rs=0; while(k) { if(k&1) rs=(rs+x)%mod; k>>=1; x=(x+x)%mod; } return rs; } ll qp2(ll x,ll k,ll mod) { ll rs=1; while(k) { if(k&1) rs=qc(rs,x,mod); k>>=1; x=qc(x,x,mod); } return rs; } bool Miller_Rabin(ll n) { if(n==2||n==3||n==5) return 1; if(n<2||(n%6!=1&&n%6!=5)) return 0; ll m=n-1,t=0,x,y; while((m&1)==0) t++,m>>=1; For(i,1,TM) { x=rand()%(n-1)+1; x=qp2(x,m,n); For(j,1,t) { y=qc(x,x,n); if(y==1&&x!=1&&x!=n-1) return 0; x=y; } if(x!=1) return 0; } return 1; } ll prho(ll n,ll m) { ll x=rand()%(n-1)+1,y=0; for(ll i=1,k=1,d;y!=x;++i) { if(i==k) {y=x;k<<=1;} x=(qc(x,x,n)+m)%n; d=gcd((x-y+n)%n,n); if(d>1&&d<n) return d; } return n; } multiset<ll> G; multiset<ll>::iterator it; void find(ll n,ll m) { if(Miller_Rabin(n)) { G.insert(n); return; } ll p=n; while(p>=n) p=prho(n,m--); find(p,M); find(n/p,M); } ll g(ll x) {return qp(K,(x+1)>>1);} ll h(ll x) {return (x&1)==1? x:x>>1;} ll get_ans(ll x) { return h(x)%mod*g(x)%mod; } ll dfs(int pos,ll now,ll x) { ll rs=0; if(pos>tot) { ll d=n/now; if((d&1)&&!(now&1)) rs=0; else rs=get_ans(n/now)*x%mod; // printf("dfs:%lld: x=%lld,rs=%lld\n",now,x,rs); return rs; } For(i,0,sum[pos]) { rs+=dfs(pos+1,now,i? (1-p[pos]%mod+mod)%mod*x%mod:x); rs%=mod; now*=p[pos]; } return rs%mod; } void clear() { For(i,1,tot) sum[i]=0; tot=0; G.clear(); } int main() { read(Td); while(Td--) { clear(); read(n); read(K); read(mod); if(n!=1) find(n,M); for(it=G.begin();it!=G.end();++it) { if(*it!=p[tot]) p[++tot]=*it; ++sum[tot]; } printf("%lld\n",dfs(1,1,1)); } // cerr<<clock()<<"\n"; return 0; }
D2T1 原题识别
还没看,等着Achen做起了给我讲
D2T2 旧试题
听Achen讲这道题,记不起来约数是什么了……
充分体现出自己多么智障
题解:https://www.luogu.org/problemnew/solution/P4619
D2T3 荣誉称号
明显一棵完全二叉树的样子,然后发现下面的一堆和上面的同余,可以直接归到上面去dp就好了
//Serene #include<algorithm> #include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<cmath> using namespace std; #define ll long long #define db double #define For(i,a,b) for(int i=(a);i<=(b);++i) #define Rep(i,a,b) for(int i=(a);i>=(b);--i) const ll INF=1e16; const int maxn=(1<<12)+7,maxm=200+7,maxt=1e7+7; int Td,n,k,m,U,a[maxt],b[maxt]; ll sum[maxn][maxm],v[maxm][maxm],cst[maxn][maxm],dp[maxn][maxm]; char cc;ll ff; template<typename T>void read(T& aa) { aa=0;ff=1; cc=getchar(); while(cc!='-'&&(cc<'0'||cc>'9')) cc=getchar(); if(cc=='-') ff=-1,cc=getchar(); while(cc>='0'&&cc<='9') aa=aa*10+cc-'0',cc=getchar(); aa*=ff; } unsigned int SA, SB, SC;int pd, A, B; unsigned int rng61(){ SA ^= SA << 16; SA ^= SA >> 5; SA ^= SA << 1; unsigned int t = SA; SA = SB; SB = SC; SC ^= t ^ SA; return SC; } void init(){ scanf("%d%d%d%d%u%u%u%d%d", &n, &k, &m, &pd, &SA, &SB, &SC, &A, &B); for(int i = 1; i <= pd; i++)scanf("%d%d", &a[i], &b[i]); for(int i = pd + 1; i <= n; i++){ a[i] = rng61() % A + 1; b[i] = rng61() % B + 1; } } void clear() { For(i,1,U) For(j,0,m) sum[i][j]=cst[i][j]=0; } int main() { read(Td); int x,y; while(Td--) { init(); clear(); x=k+1; y=0; U=(1<<k+1)-1; For(i,1,U) sum[i][a[i]%m]=(ll)b[i]; For(i,U+1,n) { if((i>>x)>1) x++,y=x%(k+1); sum[i>>(x-y)][a[i]%m]+=(ll)b[i]; } For(i,0,m-1) For(j,0,m-1) v[i][j]=i<=j? j-i:j+m-i; For(i,1,U) For(j,0,m-1) For(k,0,m-1) cst[i][j]+=sum[i][k]*v[k][j]; For(i,1,U) For(j,0,m) dp[i][j]=INF; For(i,(1<<k),U) For(j,0,m-1) dp[i][j]=cst[i][j]; Rep(i,(1<<k)-1,1) For(j,0,m-1) { For(t,0,m-1) { x=(j-t+m)%m; dp[i][j]=min(dp[i][j],cst[i][t]+dp[i<<1][x]+dp[i<<1|1][x]); } } printf("%lld\n",dp[1][0]); } return 0; }
弱者就是会被欺负呀