ACM2019陕西省赛-ZOJ4128-0689(思维)

题目链接
We call a string as a 0689-string if this string only consists of digits ‘0’, ‘6’, ‘8’ and ‘9’. Given a 0689-string ss of length nn, one must do the following operation exactly once: select a non-empty substring of ss and rotate it 180 degrees.
More formally, let sis_i be the ii-th character in string ss. After rotating the substring starting from sls_l and ending at srs_r 180 degrees (1lrn1 \le l \le r \le n), string ss will become string tt of length nn extracted from the following equation, where tit_i indicates the ii-th character in string tt: ti={siif 1i<l or r<in’0’if lir and sl+ri=’0’’6’if lir and sl+ri=’9’’8’if lir and sl+ri=’8’’9’if lir and sl+ri=’6’t_i = \begin{cases} s_i & \text{if } 1 \le i < l \text{ or } r < i \le n \\ \text{'0'} & \text{if } l \le i \le r \text{ and } s_{l+r-i} = \text{'0'} \\ \text{'6'} & \text{if } l \le i \le r \text{ and } s_{l+r-i} = \text{'9'} \\ \text{'8'} & \text{if } l \le i \le r \text{ and } s_{l+r-i} = \text{'8'} \\ \text{'9'} & \text{if } l \le i \le r \text{ and } s_{l+r-i} = \text{'6'} \\ \end{cases}
What’s the number of different strings one can get after the operation?
Input
There are multiple test cases. The first line of the input contains an integer TT, indicating the number of test cases. For each test case:
The first and only line contains a 0689-string ss (1s1061 \le |s| \le 10^6).
It’s guaranteed that the sum of s|s| of all test cases will not exceed 10710^7.
Output
For each test case output one line containing one integer, indicating the number of different strings one can get after applying the operation exactly once.
Sample Input
2
0689
08
Sample Output
8
2


题目大意

一个字符串,仅有0、6、8、9组成,选取一个子串,翻转,得到新的字符串,问新得到的字符串不同的有多少个?0,8翻转还是自己,6翻转是9,9翻转是6。

思路

不要模拟去做,肯定超时。
如果每个数都不一样,那么翻转后不同的应该是(1+n)*n/2,就是子串的个数,再算上自己本身的,是(1+n)*n/2+1,我们把重复的减去就行了。
去重,如果开头-末位是0-0,8-8,6-9,9-6的都是不行的。比如0680,翻转0680,其实还是翻转68,和开头结尾的0-0没有啥关系。
0-0的情况,统计出字符串中0的个数num,那么以0开头并以0结尾子串的个数就是(1+num)*num/2。
8-8和0-0一样。
9-6和6-9的情况,统计出字符串中9的个数x,字符串中6的个数y。6-9和9-6都是重复的,总重复的个数是x * y。
还有一个特例需要考虑,就是字符串全部为6或者全部9,这时候没有不翻转(不变)的情况。如要减去刚开始(1+n)*n/2+1中加上的1。举个栗子,字符串8,如果不算自己的那个了话,减去后就是0了,但是因为8翻转后是可以得到自己的,所以加上1,代表情况是自己。有0,有8,仅翻转一个0或一个8是可以得到自己本身的;没有0、8,只有6和9也是可以的,69在一起翻转,还是自己。唯独仅有6和仅有9的情况,翻转后一定是得不到自己的,所以要减一。

需要注意爆int的问题,需要1ll或者(ll)转化为long long

#include <bits/stdc++.h>
#define ll long long

using namespace std;
const int maxn = 1e6+8;
char s[maxn];
ll num[4];

int main() {
    int T; scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        int n = strlen(s);
        memset(num,0,sizeof(num));

        for(int i=0;i<n;i++){
            if(s[i]=='0') num[0]++;
            else if(s[i]=='6') num[1]++;
            else if(s[i]=='8') num[2]++;
            else if(s[i]=='9') num[3]++;
        }

        ll ans = (1ll+n)*n/2+1;

        ans -= (1+num[0])*num[0]/2;
        ans -= (1+num[2])*num[2]/2;
        ans -= num[1]*num[3];
        
        if(num[1]==n||num[3]==n) ans--;
        printf("%lld\n",ans);
    }
    return 0;
}

另一种不是减去,而是加的方法,比较耗内存。
写的时候遇到了算法一样,但是超时的问题。

超时

  1. 用string s; cin>>s;可能会超时。用char* s[]; scanf("%s",s);
  2. memset的锅:memset每次都要把num数组清空,T经过测试在5000以上,每次都清空num就会超时(本地只做memset也要很长时间),但是for初始化,n可能每次不是那么大,不用全部清空。
#include <bits/stdc++.h>
#define ll long long

using namespace std;
const int maxn = 1e6+8;
char s[maxn];
//string s;
int num[4][maxn];

int main() {
    int T; scanf("%d",&T);
    while(T--){
        scanf("%s",s);
        int n = strlen(s);
        //cin>>s;超时
        //int n = s.length();

        for(int i=0;i<=n;i++) num[0][i]=num[1][i]=num[2][i]=num[3][i]=0;
        //memset(num,0,sizeof(num)); 超时

        for(int i=n-1;i>=0;i--){
            num[0][i] = num[0][i+1] + (s[i]=='0');
            num[1][i] = num[1][i+1] + (s[i]=='8');
            num[2][i] = num[2][i+1] + (s[i]=='6');
            num[3][i] = num[3][i+1] + (s[i]=='9');
        }
        ll ans = 1;
        for(int i=0;i<n;i++){
            if(s[i]=='0')
                ans += num[1][i+1] + num[2][i+1] + num[3][i+1];
            else if(s[i]=='8')
                ans += num[0][i+1] + num[2][i+1] + num[3][i+1];
            else if(s[i]=='6')
                ans += num[0][i+1] + num[1][i+1] + num[2][i];
            else if(s[i]=='9')
                ans += num[0][i+1] + num[1][i+1] + num[3][i];
        }
        if(num[2][0]==n||num[3][0]==n) ans--;
        printf("%lld\n",ans);
    }
    return 0;
}
发布了62 篇原创文章 · 获赞 29 · 访问量 4749
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章