XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof
A. City Wall
找规律。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 0, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; int n; int main() { while(~scanf("%d",&n)){ int i, typ, sum, j; typ = 1; sum = 7; i = 12; while(1){ sum += typ; i ++; if(sum >= n) break; int flag = 1; for(int j = 1; j <= 4; j ++){ sum += typ + 1; i ++; //printf("%d %d\n", sum, i); if(sum >= n) {flag = 0; break;} } if(!flag) break; sum += typ + 2; i ++; if(sum >= n) break; typ ++; } if(n >= 8) printf("%d\n", i); else{ int ans; if(n == 1) ans = 6; else if(n == 2) ans = 8; else if(n == 3) ans = 9; else if(n == 4) ans = 10; else if(n == 5) ans = 11; else if(n == 6) ans = 12; else if(n == 7) ans = 12; printf("%d\n", ans); } } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
B. Domino Colorings
若已经知道了每个格子的颜色,那么可以DP判断是否能由某种骨牌铺成,设$dp[S]$表示轮廓线上$n$个点匹配状态为$S$是否可行即可。
现在不知道每个格子的颜色,那么需要DP这些颜色,设$f[i][j][c][v]$表示考虑到$(i,j)$,轮廓线上$n$个点颜色为$c$,$dp[S]$这个大小为$2^n$的布尔数组取值为$v$时的方案数。
当$n=6$时状态数也只有不到$2000$个,所以可以通过。
#include<cstdio> #include<map> using namespace std; typedef unsigned long long ll; typedef pair<int,ll>E; const int P=1000000007; int n,m,o,i,j,k,x,ans; map<E,int>f[2]; map<E,int>::iterator it; inline void up(int&a,int b){a=a+b<P?a+b:a+b-P;} inline bool check(ll S){ return S&1; } int main(){ scanf("%d%d",&n,&m); f[0][E(0,1)]=1; for(i=1;i<=m;i++){ for(j=0;j<n;j++){ f[o^1].clear(); for(it=f[o].begin();it!=f[o].end();it++){ int col=it->first.first; ll dp=it->first.second; int w=it->second; int u=col>>j&1; int l=0; if(j)l=col>>(j-1)&1; int ecol=col^(u<<j); for(k=0;k<2;k++){ int ncol=ecol^(k<<j); ll ndp=0; for(x=0;x<1<<n;x++)if(dp>>x&1){ if(x>>j&1){ if(u==k)continue; ndp|=1ULL<<(x^(1<<j)); continue; } ndp|=1ULL<<(x^(1<<j)); if(j&&l!=k)if(x>>(j-1)&1)ndp|=1ULL<<(x^(1<<(j-1))); } up(f[o^1][E(ncol,ndp)],w); } } o^=1; } } for(it=f[o].begin();it!=f[o].end();it++)if(check(it->first.second))up(ans,it->second); printf("%d",ans); }
C. Counterquestion
暴力枚举$10!$种大小关系,然后求出每种的方案数即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=500; int n,i,j,m,q[N],id[N],cnt,rk[N];char a[N]; ll f[5000000]; void write(ll S){ static ll w[1000]; for(int i=n-1;i;i--){ w[i]=S%3; S/=3; } for(i=1;i<n;i++){ putchar(a[i]); putchar(' '); if(w[i]==0)putchar('='); if(w[i]==1)putchar('<'); if(w[i]==2)putchar('>'); putchar(' '); } putchar(a[n]); } int main(){ scanf("%s",a+1); n=strlen(a+1); for(i=1;i<=n;i++){ if(!id[a[i]])id[a[i]]=++m; } for(i=1;i<=m;i++)q[i]=i; do{ for(i=1;i<=m;i++)rk[q[i]]=i; ll cur=0; for(i=1;i<n;i++){ cur*=3; if(a[i]==a[i+1])continue; if(rk[id[a[i]]]<rk[id[a[i+1]]])cur++; else cur+=2; } f[++cnt]=cur; }while(next_permutation(q+1,q+m+1)); sort(f+1,f+cnt+1); for(i=1;i<=cnt;i=j){ for(j=i;j<=cnt&&f[i]==f[j];j++); if(j==i+1){ write(f[i]); return 0; } } puts("Impossible"); }
D. Galaxy Center
首先假设$A$在$B$外层或同层,不然可以交换$AB$。
若$A$和$B$同层且距离不超过$5$,则此时直接走过去最优。
否则最优方案一定是将$A$往里走一层。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 40, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; char a[N], b[N]; LL v[N]; struct P { LL x, y; }va, vb; void mul(P &a) { ++a.x; a.y *= 3; } void div(P &a) { --a.x; a.y /= 3; } void add(P &a) { ++a.y; if(a.y == v[a.x])a.y -= v[a.x]; } void sub(P &a) { --a.y; if(a.y < 0)a.y += v[a.x]; } P know(char s[N]) { P now = {0, 0}; for(int i = 0; s[i]; ++i) { if(s[i] == 'c') { mul(now); } else if(s[i] == 'g') { div(now); } else if(s[i] == 's') { add(now); } else if(s[i] == 'a') { sub(now); } else {puts("s[i] = ?"); while(1);} } return now; } void print(P a) { printf("%lld %lld\n", a.x, a.y); } string GO(P a, P b) { if(a.x == b.x && a.y == b.y)return ""; string ans = ""; bool swp = 0; if(a.x < b.x) { swp = 1; swap(a, b); } LL by = b.y * v[a.x - b.x]; LL disS = by - a.y; if(disS < 0)disS += v[a.x]; LL disA = a.y - by; if(disA < 0)disA += v[a.x]; bool flag = 0; if(a.x == b.x) { if(disS < disA) { if(disS <= 5) { while(disS) { --disS; add(a); ans += 's'; } flag = 1; } } else if(disA < disS) { if(disA <= 5) { while(disA) { --disA; sub(a); ans += 'a'; } flag = 1; } } } if(!flag) { if(a.y % 3 == 1) { sub(a); ans += 'a'; } else if(a.y % 3 == 2) { add(a); ans += 's'; } div(a); ans += 'g'; } ans += GO(a, b); if(swp) { int len = ans.size(); for(int i = 0; i < len / 2; ++i) { swap(ans[i], ans[len - 1 - i]); } for(int i = 0; i < len; ++i) { if(ans[i] == 's')ans[i] = 'a'; else if(ans[i] == 'a')ans[i] = 's'; else if(ans[i] == 'c')ans[i] = 'g'; else if(ans[i] == 'g')ans[i] = 'c'; else {puts("ans[i] = ?"); while(1);} } } return ans; } int main() { v[0] = 1; for(int i = 1; i <= 36; ++i)v[i] = v[i - 1] * 3; while(~scanf("%s%s", a, b)) { //print(know(a)); print(know(b)); cout << GO(know(a), know(b)) << endl; } return 0; } /* 【trick&&吐槽】 cccs cs cg cg cg ccaaa ccc csss cccsca cccacs csss ccc cccacs cccsca cccs csscc csscc cccs 【题意】 【分析】 【时间复杂度&&优化】 */
E. IBM 1403
预处理出$f[i][j]$表示模式串第$i$个位置之后第一个字符$j$的位置,对于每一行计算需要的最大时间即可。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1000010; typedef long long ll; int L,n,i,j,cur,f[100010][130]; char a[N],b[N]; ll ans; int main(){ gets(a); L=strlen(a); for(i=L-1;~i;i--)f[L][a[i]]=i; for(i=L-1;~i;i--){ for(j=0;j<130;j++)f[i][j]=f[i+1][j]; f[i][a[i]]=i; } while(gets(b)){ n=strlen(b); int tmp=0; for(i=0;i<n;i++){ char x=b[i]; if(x==' ')continue; int nxt=((f[(cur+i)%L][x]-(cur+i))%L+L)%L; if(nxt>tmp)tmp=nxt; } tmp++; ans+=tmp; cur=(cur+tmp)%L; } printf("%lld",ans); }
F. Line Tracing
留坑。
G. The Queen and the Knight
当$n\leq 30$时,可以$O(n^5)$BFS出所有局面下的最优策略。
当$n>30$时,可以先逼近骑士,然后分类构造。
H. Product of Roots
\[\begin{eqnarray*}
f(x)&=&\prod_{i=1}^n(1+a_ix)\\
&=&\exp\left(\sum_{i=1}^n\ln(1+a_ix)\right)
\end{eqnarray*}\]
将$\ln(1+a_ix)$泰勒展开,有:
\[\begin{eqnarray*}
f(x)&=&\exp\left(\sum_{i=1}^n\ln(1+a_ix)\right)\\
&=&\exp\left(\sum_{i=1}^n\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^ja_i^j\right)\\
&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^j\sum_{i=1}^n a_i^j\right)\\
&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^jA_j\right)\\
\end{eqnarray*}\]
对于$g$和$h$同理,则:
\[\begin{eqnarray*}
g(x)&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^jB_j\right)\\
h(x)&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^j\sum_{i=1}^n\sum_{k=1}^m a_i^jb_k^j\right)\\
&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^j\sum_{i=1}^n a_i^j\sum_{k=1}^m b_k^j\right)\\
&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^jA_jB_j\right)\\
&=&\exp\left(\sum_{j\geq 1}\frac{(-1)^{j+1}}{j}x^jC_j\right)
\end{eqnarray*}\]
多项式$\ln$求出所有$A_i$和$B_i$,令$C_i=A_iB_i$,然后按上式用多项式$\exp$计算$h$即可。
时间复杂度$O(n\log n)$。
#include<cstdio> typedef long long ll; const int N=262144,K=17; int n,m,i,k,_; int a[N+10],b[N+10],c[N+10],tmp[N+10],tmp2[N+10]; int P=998244353,G=3,g[K+1],ng[K+10],inv[N+10],inv2; inline int pow(int a,int b){int t=1;for(;b;b>>=1,a=(ll)a*a%P)if(b&1)t=(ll)t*a%P;return t;} inline void NTT(int*a,int n,int t){ for(int i=1,j=0;i<n-1;i++){ for(int s=n;j^=s>>=1,~j&s;); if(i<j){int k=a[i];a[i]=a[j];a[j]=k;} } for(int d=0;(1<<d)<n;d++){ int m=1<<d,m2=m<<1,_w=t==1?g[d]:ng[d]; for(int i=0;i<n;i+=m2)for(int w=1,j=0;j<m;j++){ int&A=a[i+j+m],&B=a[i+j],t=(ll)w*A%P; A=B-t;if(A<0)A+=P; B=B+t;if(B>=P)B-=P; w=(ll)w*_w%P; } } if(t==-1)for(int i=0,j=inv[n];i<n;i++)a[i]=(ll)a[i]*j%P; } void getinv(int*a,int*b,int n){ if(n==1){b[0]=pow(a[0],P-2);return;} getinv(a,b,n>>1); int k=n<<1,i; for(i=0;i<n;i++)tmp[i]=a[i]; for(i=n;i<k;i++)tmp[i]=b[i]=0; NTT(tmp,k,1),NTT(b,k,1); for(i=0;i<k;i++){ b[i]=(ll)b[i]*(2-(ll)tmp[i]*b[i]%P)%P; if(b[i]<0)b[i]+=P; } NTT(b,k,-1); for(i=n;i<k;i++)b[i]=0; } inline void getln(int*a,int*b,int n){ getinv(a,tmp2,n); int k=n<<1,i; for(i=0;i<n-1;i++)b[i]=(ll)a[i+1]*(i+1)%P; for(i=n-1;i<k;i++)b[i]=0; NTT(b,k,1),NTT(tmp2,k,1); for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp2[i]%P; NTT(b,k,-1); for(i=n-1;i;i--)b[i]=(ll)b[i-1]*inv[i]%P;b[0]=0; } void getexp(int*a,int*b,int n){ if(n==1){b[0]=1;return;} getexp(a,b,n>>1); getln(b,tmp,n); int k=n<<1,i; for(i=0;i<n;i++){tmp[i]=a[i]-tmp[i];if(tmp[i]<0)tmp[i]+=P;} if((++tmp[0])==P)tmp[0]=0; for(i=n;i<k;i++)tmp[i]=b[i]=0; NTT(tmp,k,1),NTT(b,k,1); for(i=0;i<k;i++)b[i]=(ll)b[i]*tmp[i]%P; NTT(b,k,-1); for(i=n;i<k;i++)b[i]=0; } int main(){ for(g[K]=pow(G,(P-1)/N),ng[K]=pow(g[K],P-2),i=K-1;~i;i--)g[i]=(ll)g[i+1]*g[i+1]%P,ng[i]=(ll)ng[i+1]*ng[i+1]%P; for(inv[1]=1,i=2;i<=N;i++)inv[i]=(ll)(P-inv[P%i])*(P/i)%P;inv2=inv[2]; scanf("%d%d%d",&n,&m,&_); k=131072; for(i=0;i<=n;i++)scanf("%d",&a[i]); getln(a,c,k); for(i=0;i<k;i++)a[i]=c[i],c[i]=0; for(i=0;i<=m;i++)scanf("%d",&b[i]); getln(b,c,k); for(i=0;i<k;i++)a[i]=1LL*a[i]*c[i]%P,b[i]=0; for(i=0;i<k;i+=2)a[i]=(P-a[i])%P; for(i=1;i<k;i++)a[i]=1LL*a[i]*i%P; getexp(a,b,k); for(i=0;i<_;i++)printf("%d ",b[i]); return 0; }
I. Safe Landing
按题意模拟。
#include<stdio.h> #include<iostream> #include<string.h> #include<string> #include<ctype.h> #include<math.h> #include<set> #include<map> #include<vector> #include<queue> #include<bitset> #include<algorithm> #include<time.h> using namespace std; void fre() { } #define MS(x, y) memset(x, y, sizeof(x)) #define ls o<<1 #define rs o<<1|1 typedef long long LL; typedef unsigned long long UL; typedef unsigned int UI; template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b > a)a = b; } template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b < a)a = b; } const int N = 1e5 + 10, M = 0, Z = 1e9 + 7, inf = 0x3f3f3f3f; template <class T1, class T2>inline void gadd(T1 &a, T2 b) { a = (a + b) % Z; } int casenum, casei; char s[N]; bool v[128]; int main() { while(~scanf("%s",s)) { MS(v, 0); int cnt = 0; for(int i = 0; s[i]; ++i) { if(!v[s[i]])++cnt; v[s[i]] = 1; } if(cnt <= 1)puts("X"); else if(cnt == 3) { if(!v['N'])puts("N"); else if(!v['S'])puts("S"); else if(!v['W'])puts("W"); else if(!v['E'])puts("E"); else while(1); } else if(cnt == 2) { if(v['N'] && v['W']) puts("SE"); else if(v['N'] && v['E'])puts("SW"); else if(v['S'] && v['W']) puts("NE"); else if(v['S'] && v['E'])puts("NW"); else puts("X"); } else while(1); } return 0; } /* 【trick&&吐槽】 【题意】 【分析】 【时间复杂度&&优化】 */
J. Perfect Square
取$20$个大质数,然后检查$x^2\bmod p=n$是否有解即可。
根据二次剩余,这等价于$n^{\frac{p-1}{2}}\bmod p=1$。
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> using namespace std; typedef long long ll; const int N=1000010; int n,i,cnt;char a[N]; bool isprime(int n){ for(int i=2;i<=n/i;i++)if(n%i==0)return 0; return 1; } ll powmod(ll a,ll b,ll P){ ll t=1; for(;b;b>>=1,a=a*a%P)if(b&1)t=t*a%P; return t; } bool work(ll n,ll p){ if(n==0||n==1)return 1; if(powmod(n,p>>1,p)!=1)return 0; return 1; } bool check(int P){ ll ret=0; for(int i=1;i<=n;i++)ret=(ret*10+a[i]-'0')%P; return work(ret,P); } int main(){ scanf("%s",a+1); n=strlen(a+1); for(i=1000000000;;i++)if(isprime(i)){ if(!check(i))return puts("No"),0; cnt++; if(cnt>=20)return puts("Yes"),0; } }