• 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
    ", 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
    ", 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
    ", 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
    ", 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

    当$nleq 30$时,可以$O(n^5)$BFS出所有局面下的最优策略。

    当$n>30$时,可以先逼近骑士,然后分类构造。

    H. Product of Roots

    [egin{eqnarray*}
    f(x)&=&prod_{i=1}^n(1+a_ix)\
    &=&expleft(sum_{i=1}^nln(1+a_ix) ight)
    end{eqnarray*}]

    将$ln(1+a_ix)$泰勒展开,有:

    [egin{eqnarray*}
    f(x)&=&expleft(sum_{i=1}^nln(1+a_ix) ight)\
    &=&expleft(sum_{i=1}^nsum_{jgeq 1}frac{(-1)^{j+1}}{j}x^ja_i^j ight)\
    &=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jsum_{i=1}^n a_i^j ight)\
    &=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jA_j ight)\
    end{eqnarray*}]

    对于$g$和$h$同理,则:

    [egin{eqnarray*}
    g(x)&=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jB_j ight)\
    h(x)&=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jsum_{i=1}^nsum_{k=1}^m a_i^jb_k^j ight)\
    &=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jsum_{i=1}^n a_i^jsum_{k=1}^m b_k^j ight)\
    &=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jA_jB_j ight)\
    &=&expleft(sum_{jgeq 1}frac{(-1)^{j+1}}{j}x^jC_j ight)
    end{eqnarray*}]

    多项式$ln$求出所有$A_i$和$B_i$,令$C_i=A_iB_i$,然后按上式用多项式$exp$计算$h$即可。

    时间复杂度$O(nlog 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^2mod p=n$是否有解即可。

    根据二次剩余,这等价于$n^{frac{p-1}{2}}mod 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;
    	}
    }
    

      

  • 相关阅读:
    高级数据结构实现——自顶向下伸展树
    优先队列——二项队列(binominal queue)
    优先队列——左式堆
    近似装箱问题(两种脱机算法实现)
    近似装箱问题(三种联机算法实现)
    Instruments
    CALayer之 customizing timing of an animation
    PKCS填充方式
    使用Xcode和Instruments调试解决iOS内存泄露
    apple网址
  • 原文地址:https://www.cnblogs.com/clrs97/p/8636147.html
Copyright © 2020-2023  润新知