XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof

Claris發表於2018-03-24

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;
	}
}

  

相關文章