Panasonic Programming Contest 2020
A - Kth Term
#include <bits/stdc++.h> #define ll long long using namespace std; int a[32]={1, 1, 1, 2, 1, 2, 1, 5, 2, 2, 1, 5, 1, 2, 1, 14, 1, 5, 1, 5, 2, 2, 1, 15, 2, 2, 5, 4, 1, 4, 1, 51}; int main() { //freopen("in.txt","r",stdin); int n; scanf("%d",&n); printf("%d\n",a[n-1]); return 0; }
B - Bishop
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { //freopen("in.txt","r",stdin); ll n,m; scanf("%lld%lld",&n,&m); if(n==1||m==1) printf("1\n"); else printf("%lld\n",((n+1)/2)*((m+1)/2)+(n/2)*(m/2)); return 0; }
C - Sqrt Inequality
题意:给三个正整数a,b,c,判断$\sqrt{a}+\sqrt{b}<\sqrt{c}$是否成立。
数据范围:$1\leq a,b,c \leq 10^{9}$
题解:$\sqrt{a}+\sqrt{b}<\sqrt{c}\Rightarrow a+b+\sqrt{4\times a \times b} <c\Rightarrow \sqrt{4\times a \times b}<=c-a-b$,若$c-a-b\geq 0$,再将两边同时平方即可。
#include <bits/stdc++.h> #define ll long long using namespace std; int main() { //freopen("in.txt","r",stdin); ll a,b,c; scanf("%lld%lld%lld",&a,&b,&c); if(a+b>=c) printf("No\n"); else { c=c-a-b; if(4*a*b>=c*c) printf("No\n"); else printf("Yes\n"); } return 0; }
D - String Equivalence
题意:按字典序输出长度为N且只含有小写字母的字符串,满足当前输出的字符串与之前输出的字符串不同构。
数据范围:$1\leq N \leq 10$
题解:每一次往后面添一个字母,且该字母不能比之前的最大字母大2。
#include <bits/stdc++.h> #define ll long long using namespace std; char s[105]; int n; void dfs(int pos,int x,int up) { s[pos]=x+'a'; if(pos==n-1) { printf("%s\n",s); return; } for(int i=0;i<=up+1;i++) { dfs(pos+1,i,max(up,i)); } } int main() { //freopen("in.txt","r",stdin); scanf("%d",&n),s[n]='\0'; dfs(0,0,0); return 0; }
E - Three Substrings
题意:找一个最短的字符串,满足字符串a,b,c是该字符串的子串,a,b,c包含小写字母和'?','?'可以看成任意字母。
数据范围:$1\leq \left | a \right |,\left | b \right |,\left | c \right | \leq 2000$
题解:以字符串a为基准,相当于看字符串b,c在a的哪个位置,处理出ab,ac,bc,字符串偏移x是否满足要求,然后枚举b,c的偏移即可。
具体细节看代码。
#include <bits/stdc++.h> #define ll long long using namespace std; const int N=2e3+5; const int M=2e4+5; char a[N],b[N],c[N]; bool ab[M],ac[M],bc[M];//true为不满足 bool cal(char a,char b) { return a=='?'||b=='?'||a==b; } int main() { //freopen("in.txt","r",stdin); scanf("%s%s%s",a,b,c); int A=strlen(a),B=strlen(b),C=strlen(c); for(int i=0;i<A;i++) { for(int j=0;j<B;j++) { if(!cal(a[i],b[j])) ab[i-j+4000]=true; } for(int j=0;j<C;j++) { if(!cal(a[i],c[j])) ac[i-j+4000]=true; } } for(int i=0;i<B;i++) { for(int j=0;j<C;j++) { if(!cal(b[i],c[j])) bc[i-j+4000]=true; } } int ans=1e9; for(int i=-4000;i<=4000;i++) {//2倍因为可能存在bca之类的情况 for(int j=-4000;j<=4000;j++) { if(!ab[i+4000]&&!ac[j+4000]&&!bc[j-i+4000]) { int L=min(0,min(i,j)),R=max(A,max(B+i,C+j)); ans=min(ans,R-L); } } } printf("%d\n",ans); return 0; }
F - Fractal Shortest Path
题意:给一个无限大的图(具体看题目),格点为黑的表示不能走,Q组查询,$(a_{i},b_{i})$到$(c_{i},d_{i})$的最短距离。
数据范围:$1 \leq Q \leq 10000,1 \leq a_{i},b_{i},c_{i},d_{i} \leq 3^{30}$
题解:将图分为9块,其中123为一层,456为一层,789为一层。
1.两点在不同层(除了2,8):两点之间的距离即为两点欧几里得距离,为了避免(2,8)这种情况,可以通过交换(x,y)转化为(4,6)。
2.两点在同一层,并且不在456这层:可以往下递归,y轴保持不变。
3.两点在同一层,并且在456这层:由于需要绕过中间这块,只要判断往上走还是往下走即可。
#include <bits/stdc++.h> #define ll long long using namespace std; ll width[35]={1}; ll cal(ll x1,ll y1,ll x2,ll y2,int level) { if(level==0) return abs(y1-y2); ll w=width[level-1]; if(x1/w!=x2/w) return abs(x1-x2)+abs(y1-y2);//不同层 if(x1/w==1&&abs(y1/w-y2/w)>=2) {//同层且在456这层 return min(x1%w+x2%w+2,w*2-x1%w-x2%w)+abs(y1-y2); } return cal(x1%w,y1,x2%w,y2,level-1); } int main() { //freopen("in.txt","r",stdin); for(int i=1;i<35;i++) width[i]=width[i-1]*3; int T; scanf("%d",&T); while(T--) { ll a,b,c,d; scanf("%lld%lld%lld%lld",&a,&b,&c,&d),a--,b--,c--,d--; if(abs(a-c)>abs(b-d)) swap(a,b),swap(c,d);//避免(2,8) printf("%lld\n",cal(a,b,c,d,30)); } return 0; }