题目让我们从小到大输出1e6以内所有的答案,其实也没什么好的思路
就是将一个数n的所有位都拆出来,遍历这些位(每次取一个x),然后通过作除法(y = n / x)得到另一个值y
如果y的构成与去掉x之后的n一样,那n就是满足条件的答案。
- #include
- #include
- 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<"\n";
- }
- }
这个生成函数其实比较类似之前做过的某种题,那题对时间复杂度要求更高,要求先对生成式的各个系数进行分类讨论,然后加上局部暴力求解
这题似乎直接暴力生成,一旦遇到了生成过的就break,注意0无论什么时候都会被第一个生成(S0=0)
- #include
- #include
- #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";
- }
- }
硬模拟每个位置添加万能字符('#'),再双指针验证答案正确性即可
- #include
- #include
- using namespace std;
- char buf[1010];
- string tmp;
- bool check(string var){
- int l = 0,r = var.size()-1;
- while(l
- 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
(2的k次方小于等于tmp[i]时肯定不用找,又因为j下标大于i,题目保证数据的递增性,所以2的k次方起码满足2^k>2*tmp[i]才进行查找)
我一开始直接用map,预先将每个值映射为对应的下标,但好像这样会高频率的访问,导致耗时较多,这里看了谢大的题解,用二分查找,也是勉强过了
- #include
- #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]
1; - else r=mid-1;
- }
- if(tmp[l]==target)return true;
- return false;
- }
- ll solve(){
- cin>>n;
- for(int i = 0;i
- cin>>tmp[i];
- }
- if(n==1)return 0;
- ll ans = 0,maxcnt=0;
- for(int i = 0;i
- if(tmp[n-1]+tmp[n-2]>=mol[i])maxcnt=i;
- else break;
- }
- for(int i = 0;i
-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
- 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"; - break;
- }
- n--;
- }
- }
- return 0;
- }
6.1559奇偶数位
简单的模拟题,暴力按顺序取,然后不断循环直到只有1位break
记得看清楚题,不要读错题了像我一样还tle,wa。。。
- #include
- 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
- 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
- #include
- 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<
"\n"; - }
- return 0;
- }
8.1530Game
游戏模拟:可以将一局游戏分为三个部分
1.开始:判断当前游戏是否开始(一个标记)(如果未开始则需要输出)
2.判断结果:判断当前游戏是否分出胜负(一个标记)(未分出胜负要输出change,分出了的话在下一步输出,所以还要一个标记)
3.结束:结束了要输出谁赢(并且将当前游戏是否开始标记为false)
- #include
- #include
- 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<
" start game "<"\n"; - }
- void sayWinner(string x,int n){
- cout<
" win game "<"\n"; - }
- void sayChange(string x){
- cout<<"Change to "<
"\n"; - }
- void sayEnd(int a,int b){
- cout<<"Game over "<":"<"\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
- #include
- 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<
'\n'; - }
- return 0;
- }
10.1539区间
这应该是前面十道题里比较需要思考的枚举题了
需要对区间这个概念比较敏感,能知道对于某一特定区间,知道端点下标就能取到该区间内某个数
那么自然就会想到用前缀和计算某一区间内包含字母的个数,对于一特定字母:用完整区间的个数减掉该区间就是剩下的个数
这里我一开始是没想到前缀和的,毕竟很久没做过和区间有关的题了,看了谢大的思路后用O(n²)水过了,但是对于某一区间,我们长度从1枚举到***的时间复杂度肯定不如直接二分。
但其实二分也有一点小处理,因为我们直接枚举长度没法包含所有左右端点的情况,所以枚举一个端点,而另一个端点用二分查找,通过端点的距离也可以算出当前的长度
所以参考了另一位同学的做法,将600+ms的通过时间优化到了30ms
- #include
- #include
- 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
- #include
- 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
// 枚举左端点 - 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;
- }//最终的查找结果为l
- if(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
- #include
- 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
" "; - }
- 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
- 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<
'/'<<(2*r+2*h)/mod<<"\n"; - }
- return 0;
- }
13.1576分段
一句话题意:逆天中的逆天,居然又是枚举,又是因子
这题自己做的时候脑海中无数的二分,贪心的叠加式,还写了个很二笔的暴力
其实考虑过累加和,也考虑过子段和的k倍必是累加和,额就是没想到直接验证累加和的所有因子
- #include
- 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
- #include
- 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
- 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
- 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
- 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
- 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
- #include
- 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
1] == ans[i])i++; - printf("%d", ans[i]);
- if (i + 1 < cnt)printf(" ");
- else printf("\n");
- }
- }
- }
- return 0;
- }
18.1567三个矩形和一个正方形
这个枚举题一开始确实不知道从何下手,谢大的思路还是很独特,实现也比较简单
要构成正方形一定可以拆分为先拿两个构成新矩形,再用新矩形去构造结果矩形(这个矩形如果两边相等即为正方形,用谢大思路如果面积为平方数好像也行)
- #include
- using namespace std;
- int matrix[3][2];
- int pre[2]; // a为第一个合成矩形中的公共边,b为两个小矩形拼接成的新边
- bool check(int x,int y){// 拿下标非x非y的那一个矩形与prea,preb进行check
- int 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
- #include
- 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)3
- if (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表格
这题是真的坑,虽然数据是符合题意,但有点不符合常理,总结一下所有要注意的点
- 表头硬性居中
- 第二行的排版方式字符串不计入该列最长字符串长度
- 一格中的数据会带有空格(其中前后多余空格不计)
- 第二行的字符串可以直接取头取尾直接判断属于哪一类
- 相邻两个|之间的字符串可能为纯空格,要将它等效替换为一个空格字符用来占位
- 最后一个底线输出完有换行(也就是整个表中三次输出底线都有换行)
- #include
- 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
- for(int j = 0;j
- cout<
size()<<"^^^"; - }
- cout<<"\n";
- }
- print_v();
- print_head();
- print_v();
- for (int i = 2; i < line; i++)print_unit(i);
- print_v();
- return 0;
- }
-
相关阅读:
Linux内存管理(六):内存模型SPARSEMEM初始化
useState源码解读 及 手撕 useState 实现
不同数据库行号关联问题
数组指针的使用
Stream流式处理
微前端:qiankun的依赖import-html-entry的作用
jsp+ssm+maven美容院管理系统--idea mysql
PyCharm 虚拟环境搭建
[性能优化] 使用 esbuild 为你的构建提速
小红书2022上半年品牌营销数据报告
-
原文地址:https://blog.csdn.net/G_yyyy/article/details/137287947