2024Xtu程设第一次练习题解

程设练习题谢大会专门查重


1.1531奇怪的数字

题目让我们从小到大输出1e6以内所有的答案,其实也没什么好的思路

就是将一个数n的所有位都拆出来,遍历这些位(每次取一个x),然后通过作除法(y = n / x)得到另一个值y

如果y的构成与去掉x之后的n一样,那n就是满足条件的答案。

#include<iostream>
#include<vector>
const int maxn = 1000000;
using namespace std;
bool solve(int n) {vector<int>TMP(10,0);int var = n,cnt = 0;while(var) {TMP[var%10]++;var/=10;cnt++;}for(int i = 9; i>=2; i--) {if(!TMP[i] || n%i !=0)continue;int y = n/i,N = 0;bool sign = true;vector<int>v(TMP);v[i]--;while(y) {if((--v[y%10])<0) {sign = false;break;}N++;y/=10;}if(N!=cnt-1)sign = false;if(sign) return true;}return false;
}
int main() {ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);for(int i = 126; i<=maxn; i++) {if(solve(i))cout<<i<<"\n";}
}

2.1542数列

这个生成函数其实比较类似之前做过的某种题,那题对时间复杂度要求更高,要求先对生成式的各个系数进行分类讨论,然后加上局部暴力求解

这题似乎直接暴力生成,一旦遇到了生成过的就break,注意0无论什么时候都会被第一个生成(S0=0)

#include<iostream>
#include<vector>
#define ll long long
using namespace std;
ll a,b,m;
ll solve(){vector<int>vis(m+1,0);vis[0]++;ll pre = 0;while(1){ pre = (a*pre+b)%m;if(vis[pre])break;vis[pre]++;}for(int i = 0;i<=m;i++){if(vis[i]==0)return i;    }
}
int main() {ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);int t;cin>>t;while(t--){cin>>a>>b>>m;cout<<solve()<<"\n";}
}

3.1548回文串

硬模拟每个位置添加万能字符('#'),再双指针验证答案正确性即可

#include<iostream>
#include<string>
using namespace std;
char buf[1010];
string tmp;
bool check(string var){int l = 0,r = var.size()-1;while(l<r){if(var[l] == var[r] || var[l]=='#' || var[r] == '#'){l++;r--;}else return false;}return true;
}
int solve(){int ans = 0;for(int i = 0;i<=tmp.size();i++){string var = tmp;var.insert(i,1,'#');ans += check(var);}return ans;
}
int main(){ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);while(scanf("%s",buf)!=EOF){tmp.clear();for(int i = 0;buf[i]!='\0';i++){tmp+=buf[i];}cout<<solve()<<"\n";}return 0;
}

4.1549 2的幂次I

首先对时间复杂度判断,直接双重循环O(n²)明显不行

然后我们肯定是要预处理2的次方的,存入一个数组中,最大值为刚刚超过2e9,作为边界值

这时候明显可以根据2的k次方,以及我们遍历的一个tmp[i],用减法得到另一个数y,因为要保证下标i<j,所以直接在i+1~n-1上找这个数y

(2的k次方小于等于tmp[i]时肯定不用找,又因为j下标大于i,题目保证数据的递增性,所以2的k次方起码满足2^k>2*tmp[i]才进行查找)

我一开始直接用map,预先将每个值映射为对应的下标,但好像这样会高频率的访问,导致耗时较多,这里看了谢大的题解,用二分查找,也是勉强过了

#include<iostream>
#define ll long long
using namespace std;
int cnt = 1, n;
const int maxn = 1e5 + 2;
ll mol[32];
ll tmp[maxn];
bool get(int l,int target){int r = n-1;while(l<=r){int mid = (l+r)>>1;if(tmp[mid]<target)l=mid+1;else r=mid-1;}if(tmp[l]==target)return true;return false;
}
ll solve(){cin>>n;for(int i = 0;i<n;i++){cin>>tmp[i];}if(n==1)return 0;ll ans = 0,maxcnt=0;for(int i = 0;i<cnt;i++){if(tmp[n-1]+tmp[n-2]>=mol[i])maxcnt=i;else break;}for(int i = 0;i<n-1;i++){for(int j = 0;j<=maxcnt;j++){if(mol[j]>2*tmp[i]){if(get(i+1,mol[j]-tmp[i]))ans++;}}}return ans;
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin>>t;mol[0] = 2;for (int i = 1;; i++) {mol[i] = mol[i - 1] * 2;cnt++;if (mol[i] > 2 * 1e9)break;}while (t--) {cout<<solve()<<"\n";}return 0;
}

5.1553数字

这题真就是典型的看着难,其实处理很简单。。。

附上我做这题的心理路线和草稿

最后这种想法的由来就是直接根据一个数,求它自己是不是合理数其实很快,但又不能提前将1e9以内的数一次性全判断完,那么每次就暴力查找它附近的数,反而成了最优解

#include<iostream>
using namespace std;
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin>>t;while(t--){int n;cin>>n;while(1){int x = n,cn=0;while(x){cn+=x%10;x/=10;}if(n%cn==0){cout<<n<<"\n";break;}n--;}}return 0;
}

6.1559奇偶数位

简单的模拟题,暴力按顺序取,然后不断循环直到只有1位break

记得看清楚题,不要读错题了像我一样还tle,wa。。。

#include<iostream>
using namespace std;
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {int ans = 0;string n;cin>>n;while(n.size()>1){int s = n.size(),a=0,b=0;for(int i = 0;i<s;i++){if(i&1)a=a*10+n[i]-'0';else b=b*10+n[i]-'0';}n = to_string(a*b);ans++;}cout << ans << "\n";}return 0;
}

7.1575四位数

四位数取出来排序,双指针取正反向的值,然后对结果进行取模赋值,简单的模拟

#include<iostream>
#include<algorithm>
using namespace std;
const int mod = 10000;
bool check(string x){if(x[0]==x[1] && x[1] == x[2] && x[2] == x[3])return true;return false;
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {int ans = 0;string var;cin >> var;while (!check(var)) {int n[4];for(int i =0;i<4;i++)n[i] = var[i]-'0';sort(n,n+4);ans++;int a = 0, b = 0;for (int i = 0; i < 4; i++) {a = a * 10 + n[i];b = b * 10 + n[3 - i] ;}int next = (a+b)%mod;for(int i = 3;i>=0;i--){var[i] = next%10 + '0';next/=10;}}cout<<ans<<"\n";}return 0;
}

8.1530Game

游戏模拟:可以将一局游戏分为三个部分

1.开始:判断当前游戏是否开始(一个标记)(如果未开始则需要输出)

2.判断结果:判断当前游戏是否分出胜负(一个标记)(未分出胜负要输出change,分出了的话在下一步输出,所以还要一个标记)

3.结束:结束了要输出谁赢(并且将当前游戏是否开始标记为false)

#include<iostream>
#include<string>
using namespace std;
string player[2]={"Alice","Bob"};
char op[4][10];
int trans(){int ans = 0;for(int i = 0;i<4;i++){if(op[i][0] == 'P')ans+=5;}return ans;
}
void start(string x,int n){cout<<x<<" start game "<<n<<"\n";
}
void sayWinner(string x,int n){cout<<x<<" win game "<<n<<"\n";
}
void sayChange(string x){cout<<"Change to "<<x<<"\n";
}
void sayEnd(int a,int b){cout<<"Game over "<<a<<":"<<b<<"\n";
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);bool isend = true,isstart = false;int cnt = 1;// 游戏局数int cnta=0,cntb=0;string winner = "Alice",nowSayer = "Alice";//赢家开始int num;while(scanf("%d%s%s%s%s",&num,op[0],op[1],op[2],op[3])!=EOF){int now = trans();if(!isstart){start(winner,cnt);isstart = true;isend = false;}if(now == num){winner = nowSayer;if(nowSayer==player[0])cnta++;else cntb++;sayWinner(winner,cnt);cnt++;isend = true;isstart = false;}if(!isend){if(nowSayer == player[0])nowSayer = player[1];else nowSayer = player[0];sayChange(nowSayer);}}sayEnd(cnta,cntb);return 0;
}

9.1538打字机

简单模拟,string比较好做,有erase和insert这种现成的函数

主要思路还是用一个下标模拟光标进行移动和增删

#include<iostream>
#include<string>
using namespace std;
char buff[550];
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);while (scanf("%s", buff) != EOF) {string ans;int p = 0;//模拟光标for (int i = 0; buff[i] != '\0'; i++) {char v = buff[i];if ((v >= 'a' && v <= 'z') || (v >= 'A' && v <= 'Z'))ans.insert(p++,1,v);switch (v) {case '[':p = 0;break;case ']':p = ans.size();break;case '<':if(p-1>=0)p--;break;case '>':if(p+1<=ans.size())p++;break;case '-':if(p-1>=0)ans.erase(--p,1);break;case '+':if(p+1<=ans.size())ans.erase(p,1);break;}}cout<<ans<<'\n';}return 0;
}

10.1539区间

这应该是前面十道题里比较需要思考的枚举题了

需要对区间这个概念比较敏感,能知道对于某一特定区间,知道端点下标就能取到该区间内某个数

那么自然就会想到用前缀和计算某一区间内包含字母的个数,对于一特定字母:用完整区间的个数减掉该区间就是剩下的个数

这里我一开始是没想到前缀和的,毕竟很久没做过和区间有关的题了,看了谢大的思路后用O(n²)水过了,但是对于某一区间,我们长度从1枚举到***的时间复杂度肯定不如直接二分。

但其实二分也有一点小处理,因为我们直接枚举长度没法包含所有左右端点的情况,所以枚举一个端点,而另一个端点用二分查找,通过端点的距离也可以算出当前的长度

所以参考了另一位同学的做法,将600+ms的通过时间优化到了30ms

#include<iostream>
#include<memory.h>
using namespace std;
int v[1010][26];
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {memset(v, 0, sizeof v);int k, ans;string tmp;cin >> k >> tmp;int n = tmp.size(), cnt = 0;ans = n;for (int i = 0; i < n; i++) {v[i][tmp[i] - 'a']++;if (i > 0)for (int j = 0; j < 26; j++)v[i][j] += v[i - 1][j];}for (int i = 0; i < 26; i++) {if (v[n - 1][i] > k)cnt++;}if (cnt == 0)cout << "0\n";else {for (int l = 0; l < n; l++) {for (int r = l; r < n; r++) {bool fair = true;for (int i = 0; i < 26; i++) {int now = v[n - 1][i] - v[r][i];if (l > 0)now += v[l - 1][i];if (now > k) {fair = false;break;}}if (fair)ans = min(r - l + 1, ans);}}cout << ans << "\n";}}return 0;
}
#include<iostream>
#include<memory.h>
using namespace std;
int v[1010][26],k,n;
bool check(int l,int r){for (int i = 0; i < 26; i++) {int now = v[n - 1][i] - v[r][i];if (l > 0)now += v[l - 1][i];if (now > k) {return false;}}return true;
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {memset(v, 0, sizeof v);int ans;string tmp;cin >> k >> tmp;n = tmp.size();int cnt = 0;ans = n;for (int i = 0; i < n; i++) {v[i][tmp[i] - 'a']++;if (i > 0)for (int j = 0; j < 26; j++)v[i][j] += v[i - 1][j];}for (int i = 0; i < 26; i++) {if (v[n - 1][i] > k)cnt++;}if (cnt == 0)cout << "0\n";else {for(int i = 0;i<n;i++){ // 枚举左端点int r = n-1,l = i;while(l<=r){ // 二分查找右端点int mid = (l+r)>>1;if(check(i,mid))r = mid-1;else l = mid+1;}//最终的查找结果为lif(check(i,l))ans = min(ans,l-i+1);}cout << ans << "\n";}}return 0;
}

11.1541卷积

题目的两个3*3矩阵卷积应该比较容易看懂,但是可能1<=n,m这个比较困惑

为什么原矩阵都没有3*3大小也能呢?其实题目中那句话很重要:

为了保持原矩阵的维度,向外扩一圈0。这个其实就保证了以原矩阵元素为中心,一定存在对应的3*3大小矩阵用来和过滤矩阵做卷积。接下来就是模拟了,我没思考优化的点,毕竟时限也不小

#include<iostream>
#include<memory.h>
using namespace std;
int buff[300][300], n, m, trans[3][3];
int work(int s, int e) {int sum = 0;for (int i = s; i <= s + 2; i++) {for (int j = e; j <= e + 2; j++) {sum += buff[i][j] * trans[i - s][j - e];}}if (sum > 255) sum = 255;if (sum < 0 ) sum = 0;return sum;
}
void solve() {for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {cout<< work(i - 1, j - 1);if(j<m)cout<<" ";}cout<<"\n";}
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while (t--) {cin >> n >> m;memset(buff, 0, sizeof buff);for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++)cin >> buff[i][j];}for (int i = 0; i < 3; i++) {for (int j = 0; j < 3; j++)cin >> trans[i][j];}solve();cout<<"\n";}return 0;
}

12.1547圆

不会证明,直接猜结论,因为排除了在弦内侧的情况,那么最特殊的点就是OC的反向延长线与圆的交点,也就是弦AB中垂线与圆的另一个交点,那么就是简单的勾股定理化简运算了

#include<iostream>
using namespace std;
int gcd(int a,int b){return a%b==0?b:gcd(b,a%b);}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin >> t;while(t--){int r,h;cin>>r>>h;int mod = gcd(r,2*r+2*h);cout<<r/mod<<'/'<<(2*r+2*h)/mod<<"\n";}return 0;
}

13.1576分段

一句话题意:逆天中的逆天,居然又是枚举,又是因子

这题自己做的时候脑海中无数的二分,贪心的叠加式,还写了个很二笔的暴力

其实考虑过累加和,也考虑过子段和的k倍必是累加和,额就是没想到直接验证累加和的所有因子

#include<iostream>
using namespace std;
int arr[100100], n, all, ans;
bool check(int a) {int var = 0;for (int i = 0; i < n; i++) {var += arr[i];if (var == a)var = 0;if (var > a)return false;}if (var && var != a)return false;return true;
}
int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &arr[i]);all += arr[i];}ans = all; // 初始化为累加和if (n == all) { // 单列最小子段和为1的情况,那样下面的循环直接从2开始枚举因子ans = 1;} else {for (int i = 2; i * i <= all; i++) {if (all % i == 0) {if (check(i)) { // 一旦 check(i)有结果,那他一定是最小的,根据因子大小排布规律可知ans = i;break;} else if (check(all / i))ans = all / i; // 因为all/i是递减的,所以这里如果有结果,要取min就直接取当前结果即可
// 但是这里不能break,因为小于sqrt(all)的那边还没check完}}}printf("%d\n", ans);return 0;
}

14.1583彩球

典型的滑动窗口题,判断右端新增颜色y之后,now[y]是否为1,以及左端删除颜色x之后,now[x]是否为0,来维护当前总颜色数量cnt

#include<iostream>
#include<memory.h>
using namespace std;
int n,m,k;
int ball[10010];
int now[10010];
void sayno(){cout<<"No\n";
}
void sayyes(){cout<<"Yes\n";
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t;cin>>t;while(t--){memset(now,0,sizeof now);cin>>n>>m>>k;for(int i = 0;i<n;i++){cin>>ball[i];}int l = 0,r = 0,cnt = 0;while(r-l+1<=m){if(now[ball[r]] == 0)cnt++;now[ball[r]]++;r++;}if(cnt!=k)sayno();else{bool sign = true;while(r<n){int old_color = ball[l++],add_color = ball[r++];if(--now[old_color] == 0)cnt--;if(++now[add_color] == 1)cnt++;if(cnt!=k){sign = false;sayno();break;}}if(sign)sayyes();}}return 0;
}

15.1484刷油漆

这道题也不是正常的模拟题,因为实际要满足时间复杂度的做法是要逆着输入的方向做。。。

(这题也是美美打开题解了)

注意这几点就能很好理解谢大的思路了:

1.后涂过的行或者列会覆盖先涂的

2.逆序遍历时,当前涂产生的颜色格子数(如果是涂行,那就是没被涂过的列数;如果是涂列,就是没被涂过的行数)

3.输入的颜色c其实就是最终结果的值是在1~c之间,直接for循环遍历即可

4.血的教训:输入到了1e4以上的规模时不会写快读就不要用cin和cout,关闭同步流也很影响时间

#include<iostream>
using namespace std;
int n, m, c, t;
int op[100010][3];
bool col[10010] = {0}, line[10010] = {0};
int ans[1010]={0};
int main() {scanf("%d%d%d%d",&n,&m,&c,&t);for (int i = 0; i < t; i++) {scanf("%d%d%d",&op[i][0],&op[i][1],&op[i][2]);}int rest_line = n, rest_col = m;for (int i = t - 1; i >= 0; i--) {if (op[i][0] == 1 && !col[op[i][1]]) {ans[op[i][2]] += rest_line;rest_col --;col[op[i][1]] = 1;} else if (op[i][0] == 0 && !line[op[i][1]]) {ans[op[i][2]] += rest_col;rest_line--;line[op[i][1]] = 1;}}for(int i = 1;i<=c;i++){if(ans[i])printf("%d %d\n",i,ans[i]);}return 0;
}

16.1556和

收到前面对于区间的感触,对于一个区间特定值的查询可以转化为前缀和的方法

这里矩阵其实处理办法也相同,只不过是将数组arr[i][j]看作是(1,1)~(i,j)的总面积,那么要求特定

(i1,j1)~(i2,j2)的面积其实就是arr[i2][j2] - arr[i1-1][j2] - arr[i2][j1-1] + arr[i1-1][j1-1]

这里自己画下图就可以理解

然后是对于数据的预处理,在构造数组的时候是需要根据题意取模的,而我们求前缀是不需要的,而且构造的时候需要乘a,b啥的,所以我们求前缀和不能与构造并行,如果并行会导致后续的构造结果出错

#include<iostream>
using namespace std;
const int maxn = 1010;
int n, m, a, b ,p , q;
int buff[maxn][maxn]={0};
void build(){// 初始化边界for(int i = 1;i<=n;i++)buff[i][1] = 1;for(int i = 1;i<=m;i++)buff[1][i] = 1;//根据题意构造for(int i = 2;i<=n;i++){for(int j = 2;j<=m;j++){buff[i][j] = (a*buff[i-1][j] + b*buff[i][j-1])%p;}}//求前缀和,因为2的这一列写法不一样,我就单独写了两个循环,避免反复的if判断减少耗时for(int i = 2;i<=m;i++)buff[1][i] = buff[1][i]+buff[1][i-1];for(int i = 2;i<=n;i++)buff[i][1] = buff[i][1]+buff[i-1][1];for(int i = 2;i<=n;i++){for(int j = 2;j<=m;j++){buff[i][j] = buff[i][j]+buff[i-1][j]+buff[i][j-1]-buff[i-1][j-1];}}
}
int main() {int t;scanf("%d",&t);while(t--){scanf("%d%d%d%d%d%d",&n,&m,&a,&b,&p,&q);build();for(int i = 1;i<=q;i++){int i1,i2,j1,j2;scanf("%d%d%d%d",&i1,&j1,&i2,&j2);int ans = buff[i2][j2] - buff[i2][j1-1] - buff[i1-1][j2] + buff[i1-1][j1-1];printf("%d\n",ans);}printf("\n");}return 0;
}

17.1560平方数

对于给定方程求解的情况,给出的参数尽量分离出来,将未知的全部放到一起,并且尽量写成乘积的形式,那样等式右边就是给定的一个常数,而左边是一个多项式乘积,将左边每个括号看作一个因子,然后根据括号内的内容反解出x的表达式

(只要我们求出因子,那每个因子都对应一个括号整体的值,那我们完全可以将一个括号看做一个新的常数,从而根据几个等式联立求出x的解)

这里也是看上题解了,但是真的很难想到方程的构造方法,但确实每次遇到都是这类做法,

一句话总结:菜!就多练!

一些写代码时要注意的点:

1.原方程的分类讨论条件中不要使用除法,(比如b*b-4*c > 0,如果写成b*b/4 - c > 0可能会造成误差)

2.题解思路中说到的两种情况(大于小于0)一定要分开求,因为解的形式是不同的,而且对应求的谁的因子也不一样

3.注意题目中说的x是大于0的整数。(不然outputlimitexceed)

4.注意从小到大输出

#include<iostream>
#include<algorithm>
using namespace std;
int cnt;
int ans[10000];
int main() {int t;scanf("%d", &t);while (t--) {cnt = 0;int b, c;scanf("%d%d", &b, &c);int res = 4 * c - b * b;if (res == 0) {printf("-1\n");continue;} else if (res > 0) {int var = res;for (int i = 1; i * i <= var; i++) {if (var % i == 0) {int p = i, q = var / i;if ((q - p - 2 * b) / 4 > 0 && (q - p - 2 * b) % 4 == 0)ans[cnt++] = (q - p - 2 * b) / 4;}}} else {int var = res * (-1);for (int i = 1; i * i <= var; i++) {if (var % i == 0) {int p = i, q = var / i;if ((p + q - 2 * b) / 4 > 0 && (p + q - 2 * b) % 4 == 0)ans[cnt++] = (p + q - 2 * b) / 4;}}}if (cnt == 0)printf("0\n");else {sort(ans, ans + cnt);for (int i = 0; i < cnt; i++) {while(i+1<cnt && ans[i+1] == ans[i])i++;printf("%d", ans[i]);if (i + 1 < cnt)printf(" ");else printf("\n");}}}return 0;
}

18.1567三个矩形和一个正方形

这个枚举题一开始确实不知道从何下手,谢大的思路还是很独特,实现也比较简单

要构成正方形一定可以拆分为先拿两个构成新矩形,再用新矩形去构造结果矩形(这个矩形如果两边相等即为正方形,用谢大思路如果面积为平方数好像也行)

#include<iostream>
using namespace std;
int matrix[3][2];
int pre[2]; // a为第一个合成矩形中的公共边,b为两个小矩形拼接成的新边
bool check(int x,int y){// 拿下标非x非y的那一个矩形与prea,preb进行checkint k;for(int i = 0;i<3;i++)if(i!=x && i!=y)k = i;for(int i = 0;i<2;i++){for(int j = 0;j<2;j++){if(matrix[k][i] == pre[j]){if(matrix[k][i] == matrix[k][(i+1)%2] + pre[(j+1)%2])return true;}}}return false;
}
bool solve(){for(int i = 0;i<2;i++){for(int j = 0;j<3;j++){if(i == j)continue;for(int k = 0;k<2;k++){for(int p = 0;p<2;p++){if(matrix[i][k] == matrix[j][p]){pre[0] = matrix[i][k];pre[1] = matrix[i][(k+1)%2] + matrix[j][(p+1)%2];if(check(i,j))return true;}}}}}return false;
}
int main() {int t;scanf("%d",&t);while(t--){for(int i = 0;i<3;i++)scanf("%d%d",&matrix[i][0],&matrix[i][1]);if(solve())printf("Yes\n");else printf("No\n");}return 0;
}

19.1578拼图

暴力递归检索四个拼图的排序状态

按顺时针方向先先检查单向对接情况,最后检查第一个和第四个的对接状况

#include<iostream>
#include<memory.h>
using namespace std;
char chosse[4][2];
char str[4][5];
bool ans, vis[4];
bool check(char a, char b) {if (a - 'a' == b - 'A' || a - 'A' == b - 'a')return true;return false;
}
void dfs(int cnt) {// 顺时针放置顺序  1(0) (1)2//			·	 (1)     (0)//          	 (0)	 (1)//				  4(1) (0)3if (ans)return ;if (cnt == 4) { // 四个拼图顺时针已符合,只差第四个和第一个的首尾拼接if (check(chosse[0][1], chosse[3][0]))ans = true;
//		for(int i = 0;i<=3;i++)printf("%c_%c ",chosse[i][0],chosse[i][1]);
//		printf("\n");return ;}for (int i = 0; i < 4; i++) {if (vis[i])continue;vis[i] = true;for (int j = 0; j < 4; j++) {// 第一个放不需要检查配对性// 检查配对性,当前的(j+1)%4号位要对上前一个chosse的0号位if (cnt == 0 || check(str[i][(j + 1) % 4], chosse[cnt - 1][0])) {chosse[cnt][0] = str[i][j];chosse[cnt][1] = str[i][(j + 1) % 4];dfs(cnt + 1);}}vis[i] = false;}
}
int main() {int t;scanf("%d", &t);while (t--) {memset(vis, false, sizeof vis);ans = false;for (int i = 0; i < 4; i++)scanf("%s", str[i]);dfs(0);if (ans)printf("Yes\n");else printf("No\n");}return 0;
}

20.1565MarkDown表格

这题是真的坑,虽然数据是符合题意,但有点不符合常理,总结一下所有要注意的点

  1. 表头硬性居中
  2. 第二行的排版方式字符串不计入该列最长字符串长度
  3. 一格中的数据会带有空格(其中前后多余空格不计)
  4. 第二行的字符串可以直接取头取尾直接判断属于哪一类
  5. 相邻两个|之间的字符串可能为纯空格,要将它等效替换为一个空格字符用来占位
  6. 最后一个底线输出完有换行(也就是整个表中三次输出底线都有换行)
#include<iostream>
using namespace std;
string str[15][15];
int maxn[15] = {0};
int way[15] = {0}; // 记录每列的排版方式,用0/1/2区分
int n;
void print_empty(int cnt) { // 输出空格数for (int i = 1; i <= cnt; i++)cout << " ";
}
void print_width(int cnt ) { // 输出边线中的'-'for (int i = 1; i <= cnt; i++)cout << "-";
}
void print_head() { // 输出头cout << "|";for (int i = 0; i < n; i++) {int all = maxn[i] + 2; // 当前列宽int all_empty = all - str[0][i].size();print_empty(all_empty / 2);cout << str[0][i];print_empty(all_empty - all_empty / 2);cout << "|";}cout << "\n";
}
void print_v() { // 输出完整边线cout << "+";for (int i = 0; i < n; i++) {print_width(maxn[i] + 2);cout << "+";}cout << "\n";
}
void print_unit(int cnt_line) { // 根据列数输出单元格的行,从2开始(0为头,1为排版方式)cout << "|";for (int i = 0; i < n; i++) {int all = maxn[i] + 2;int all_empty = all - str[cnt_line][i].size();if (way[i] == 0) {print_empty(1);cout << str[cnt_line][i];print_empty(all_empty - 1);} else if (way[i] == 2) {print_empty(all_empty - 1);cout << str[cnt_line][i];print_empty(1);} else {print_empty(all_empty / 2);cout << str[cnt_line][i];print_empty(all_empty - all_empty / 2);}cout << "|";}cout << "\n";
}
int main() {ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);string input;int line = 0;while (getline(cin, input)) {int cnt = 0; // 当前列号string var;for (int i = 0; i < input.size(); i++) {char x = input[i];if (x == '|') { // 读到 | 进行一次记录int p = var.size() - 1;while (var[p] == ' ')var.erase(p--, 1);if (var.size() == 0)var = " ";
//				var.erase(var.find_last_not_of(" ") + 1);str[line][cnt] = var;if (line != 1)maxn[cnt] = max(maxn[cnt], (int)var.size()); // 更新cnt列的最大长度cnt++;var.clear();} else if (x == ' ' && !var.empty())var += x; // 不统计前置空格else if (x != '|' && x != ' ')var += x; //统计非空格,非|的字符}// 统计最后一个字符int p = var.size() - 1;while (var[p] == ' ')var.erase(p--, 1);if (var.size() == 0)var = " ";str[line][cnt] = var;if (line != 1)maxn[cnt] = max(maxn[cnt], (int)var.size()); // 更新cnt列的最大长度cnt++;n = cnt; // 如果样例每行都是相同列数,n为列数line++;}for (int i = 0 ; i < n; i++) {string now = str[1][i]; // 第二行为排版方式字符串bool f1 = false, f2 = false;f1 = now[0] == ':';f2 = now[now.size() - 1] == ':';if ((f1 && f2) || (!f1 && !f2))way[i] = 1;else if (f1)way[i] = 0;else way[i] = 2;}for(int i = 0;i<line;i++){for(int j = 0;j<n;j++){cout<<str[i][j].size()<<"^^^";}cout<<"\n";}print_v();print_head();print_v();for (int i = 2; i < line; i++)print_unit(i);print_v();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4616.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java多态知识

目录 一、定义 二、注意事项 三、多态的好处 四、多态的弊端以及解决办法 一、定义 多态定义:多态是在继承/实现情况下的一种现象&#xff0c;表现为:对象多态、行为多态。 对象多态&#xff1a;都是同一对象&#xff0c;表现出不同角色&#xff0c;比如小明&#xff0c;…

java:SpringBoot入门

Spring 提供若干子项目,每个项目用于完成特定功能 Spring Boot 可以简化配置并且快速开发 SpringBootWeb快速入门 创建Springboot模块并使用Springweb依赖 在类上添加注解 RestController可以将字符串自动转成json返回数据给页面 再在方法上添加注解 RequestMapping(&…

python应用-socket网络编程(2)

socket 是 Python 标准库中的一个模块&#xff0c;它提供了低级别的网络通信接口。使用 socket 模块&#xff0c;你可以创建客户端和服务器应用程序&#xff0c;以便在网络上进行数据交换。 接着上文我们介绍下socket模块其他的一些函数。 目录 gettimeout() 和settimeout()…

0422empAJAX项目

数据库字段&#xff1a; 多条件查询&#xff1b; 分页查询&#xff1b; 添加图片&#xff1b; ajax离职操作&#xff1b; 删除选项&#xff0c;点击离职操作后仍然可实现删除选项

项目部署总结

1、安装jdk 第一步&#xff1a;上传jdk压缩安装包到服务器 第二步&#xff1a;将压缩安装包解压 tar -xvf jdk-8uXXX-linux-x64.tar.gz 第三步&#xff1a;配置环境变量 编辑/etc/profile文件&#xff0c;在文件末尾添加以下内容&#xff1a; export JAVA_HOME/path/to/j…

鉴权到底做什么

两种方案&#xff1a; 将 token 放在 cookie 里&#xff1b;将 token 放在请求头里&#xff0c;用 Authorization 字段。 无论对于前端还是后端而言&#xff0c;这两种方案都是各有利弊的&#xff0c;下面稍微讲几点&#xff0c;实际开发中根据需求来选用即可。 将 token 放在…

进程控制5 - exit()退出+子进程被收养+僵死进程

我们应当知道的是&#xff0c;在用fork创建子进程后&#xff0c;父子进程的执行的先后顺序是不定的&#xff0c;这时&#xff0c;我们可以用wait函数&#xff0c;wait()会暂停当前进程的执行&#xff0c;直到有信号到来或者子进程结束。总的来说&#xff0c;wait()的作用就是阻…

C语言编译的优化等级应该选哪个?O0、O1、O2还是O3

在使用IDE开发STM32程序时&#xff0c;IDE一般都会提供优化等级设置的选项&#xff0c;例如下图中KEIL软件优化等级的设置。 从上图中也可以看出&#xff0c;设置不同的优化等级&#xff0c;实际上是修改了编译器的编译参数。这个编译器是由ARM公司提供的C/C编译器armclang或者…

微信小程序Vue+nodejs+uniapp课堂教学辅助在线学习系统

uni-app框架&#xff1a;使用Vue.js开发跨平台应用的前端框架&#xff0c;编写一套代码&#xff0c;可编译到Android、小程序等平台。 后台主要实现功能&#xff1a;一、用户的管理(用户的信息管理) 二、 课程的管理&#xff08;课程发布&#xff0c;课后成绩的查看&#xff0c…

DAY 5

1. 2. #include <iostream>using namespace std; class Person {string name;int *age;public:Person():name("zhangsan"),age(new int (18)){cout << "Person的无参函数" << endl;}Person(string name,int *age):name("zhangsan&q…

水稻病害检测(YOLO数据集,多分类,稻瘟病、纹枯病、褐斑病、枯心病、霜霉病、水稻细菌性条纹斑病、稻苞虫)

是自己利用LabelImg工具进行手工标注&#xff0c;数据集制作不易&#xff0c;请尊重版权&#xff08;稻瘟病、纹枯病、褐斑病、枯心病、霜霉病、水稻细菌性条纹斑病、稻苞虫&#xff09; 如果需要yolv8检测模型和数据集放在一起的压缩包&#xff0c;可以关注&#xff1a;最新最…

聊聊Flink:Docker搭建Flink

一、准备工作 查看下Docker和Docker Compose版本&#xff0c;确保你安装了这些软件。 在 Flink 官网上下载 Flink 的 Docker 镜像。您可以使用以下命令从 Docker Hub 中下载&#xff1a; docker pull flink:1.18.0-scala_2.12 此命令将下载 Flink 1.18.0 版本的 Docker 镜像…

电商架构:系统设计+表设计

如有不对&#xff0c;请指正 欢迎评论区交流 需要哪些系统 商品系统、订单系统、权限系统、审核系统等。 商品系统 订单系统 审核系统 权限系统 参考 基于电商中台架构-商品系统设计(一) 附件

2024年【流动式起重机司机】报名考试及流动式起重机司机复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年【流动式起重机司机】报名考试及流动式起重机司机复审模拟考试&#xff0c;包含流动式起重机司机报名考试答案和解析及流动式起重机司机复审模拟考试练习。安全生产模拟考试一点通结合国家流动式起重机司机考试…

电脑已经有了一个Windows10,再多装一个Windows10组成双系统

前言 前段时间已经讲过一次双Windows系统的安装教程&#xff0c;但是小白重新去看了一下&#xff0c;发现写的内容太多&#xff0c;怕小伙伴看了之后一脸萌。 所以今天咱们就重新再来讲讲&#xff1a;在同一台机器上安装Windows10双系统的教程。 注意哦&#xff01;这里的Wi…

Android优化RecyclerView图片展示:Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas,Kotlin(b)

Android优化RecyclerView图片展示&#xff1a;Glide成堆加载批量Bitmap在RecyclerView成片绘制Canvas&#xff0c;Kotlin&#xff08;b&#xff09; 对 Android GridLayoutManager Glide批量加载Bitmap绘制Canvas画在RecyclerView&#xff0c;Kotlin&#xff08;a&#xff09;-…

【GitHub】主页简历优化

【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages&#xff08;GitHub 常用语言统计&#xff09;使用细则 3、Visitor Badge&#xff08;GitHub 访客徽章&#xff09;4、社交统计5、打字特效6、省略展示小猫 &#x1f…

求解约瑟夫问题

思路&#xff1a; 我们要创建两个指针 有一个指针pcur指向头结点&#xff0c;该pcur作为报数的指针&#xff0c;还有一个指针ptail指向尾结点&#xff0c;作为记录pcur的地址 每报数为m时&#xff0c;pcur指向下一个元素的地址&#xff0c;ptail销毁报数为m的地址&#xff0…

制糖工业智能工厂数字孪生可视化平台,推进制糖产业数字化转型

制糖工业智能工厂数字孪生可视化平台&#xff0c;推进制糖产业数字化转型。随着信息技术的快速发展&#xff0c;数字化转型已成为各行各业的重要趋势。在糖果加工制造领域&#xff0c;智能工厂数字孪生可视化平台的出现&#xff0c;为行业数字化转型注入了新的活力。 糖果加工制…

算法训练营day25

零、回溯算法理论 参考链接13.1 回溯算法 - Hello 算法 (hello-algo.com) 1.尝试与回退 之所以称之为回溯算法&#xff0c;是因为该算法在搜索解空间时会采用“尝试”与“回退”的策略。当算法在搜索过程中遇到某个状态无法继续前进或无法得到满足条件的解时&#xff0c;它会…