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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章