1. 程式人生 > >2018 ICPC Asia Qingdao Regional Contest, Online 青島,C Halting Problem 模擬 + 卡常

2018 ICPC Asia Qingdao Regional Contest, Online 青島,C Halting Problem 模擬 + 卡常

傳送門

題意:

圖靈測試是判斷一個程式能不能最終停止執行,還是永遠迴圈下去的一個概念。給你n行命令,一個變數r初始時為0,每次add後都對256取模,除了add相加命令外其餘的都是判斷符不符合某條件來決定跳轉去第k行執行命令還是不跳轉繼續執行下一行命令。如果程式最終會試圖執行n+1行輸出yes,否則輸出no。

思路:

對每行命令存一下它此時的r的值,當r的值和以前執行這次命令時的值一樣,就說明程式在迴圈直接輸出no,其餘的都為yes。

這場比賽打得很噁心。開局3道題全部1A,以優秀的罰時領先,然後開始寫這道題也很快地寫出來了,思路清晰沒有bug。但是!!被卡常了!!tmd就是找不到哪裡超時。人生第一次被卡常,用各種奇怪的方式去優化最後也沒有改對。因為r是模256的,所以同一行命令最多執行256次,第257次時r的值之前一定出現過,程式就可以結束了。時間複雜度O(n*256),給的時間只有500ms。

賽後ac,發現原因是沒有開結構體陣列而把每個變數都單獨開了一個數組。去網上找了一篇防卡常的部落格:

超時的程式碼就是因為而沒有

呵呵噠。卡到自閉。

1.在超時的情況下要多試幾種優化思路,而不是根據以前做題的經驗想當然地認為某種方法肯定不行,不能侷限自己的思維。

2.在演算法沒問題的情況下,從整個程式的結構方面優化,比如少寫內部呼叫函式。比如下面程式碼中的int opt()函式完全不需要。看了別人的程式碼,可以把opt的功能直接在主函式裡實現,這樣就不會面臨卡常的危險。結構問題儘早優化,不要犯懶在別人寫好的程式碼上微調(直接判斷不好嗎為什麼呼叫函式)

3.這次卡題非常值得反思。程式設計時大家一定要保持清醒的頭腦。

  • 附ac程式碼(偽):
//雖然過了但時間非常不友好比賽時也許仍然TLE
#include<bits/stdc++.h>

using namespace std;

struct Ins
{
    char ope;
    int v,k;
}ins[10005];
int mp[10005][257];

int r=0;
int n;
int flag;

int opt(int i)
{
    if(i>=n+1) return n+1;
    if(flag) return (n+1);
    if(ins[i].ope=='d')
    {
        if(mp[i][r]) {flag=1; return n+1;}
        else mp[i][r]++;
        r=(r+ins[i].v)%256;
        return (i+1);
    }
    else if(ins[i].ope=='e')
    {
         if(mp[i][r]) {flag=1; return n+1;}
        else mp[i][r]++;
        if(r==ins[i].v) return (ins[i].k);
        else return (i+1);
    }
    else if(ins[i].ope=='n')
    {
         if(mp[i][r]) {flag=1; return n+1;}
        else mp[i][r]++;
        if(r!=ins[i].v) return (ins[i].k);
        else return (i+1);
    }
    else if(ins[i].ope=='l')
    {
         if(mp[i][r]) {flag=1; return n+1;}
        else mp[i][r]++;
        if(r<ins[i].v) return (ins[i].k);
        else return (i+1);
    }
    else if(ins[i].ope=='g')
    {
         if(mp[i][r]) {flag=1; return n+1;}
        else mp[i][r]++;
        if(r>ins[i].v) return (ins[i].k);
        else return (i+1);
    }
    return n+1;
}
int main()
{
    int t;
    scanf("%d",&t);
    char ss[5];
    while(t--)
    {
        int f=0;
        flag=0;
        memset(ins,0,sizeof(ins));
        memset(mp,0,sizeof(mp));
        r=0;
       scanf("%d",&n);
       for(int i=1;i<=n;i++)
       {
           scanf("%s%d",ss,&ins[i].v);
           ins[i].ope=ss[1];
           if(ins[i].ope=='d') f=1;
           else scanf("%d",&ins[i].k);
       }
       if(f==0){
        for(int i=1;i<=n;i++){
            if(ins[i].ope=='e'&&ins[i].v==0&&ins[i].k<i)
            {
                flag=1;break;
            }
        }
       }
       int time=1;
       while(time<n+1)
       {
           int kk=opt(time);
           time=kk;
           if(time>=n+1) break;
           if(flag) break;
       }
       if(flag) printf("No\n");
       else printf("Yes\n");

    }
    return 0;
}

不要多次呼叫內部函式!!!能直接寫就直接寫!

不要多次呼叫內部函式!!!能直接寫就直接寫!

不要多次呼叫內部函式!!!能直接寫就直接寫!

真正的執行非常快的220ms出結果的ac程式碼:

#include<cstring>
#include<bits/stdc++.h>
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int MOD=256;
struct Ins
{
    char s[10];
    int v,k;
}ins[10005];
bool vis[10005][258];
int main()
{
    int T;int n;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%s%d",ins[i].s,&ins[i].v);
            if(ins[i].s[1]!='d')
                scanf("%d",&ins[i].k);
            //printf("%s %d %d\n",ins[i].s,ins[i].v,ins[i].k);
        }
        memset(vis,0,sizeof(vis));
        unsigned char register reg=0;
        bool flag=0;
        for(int  i=1;i<=n;)
        {
            //printf("%d %d\n",reg,i);
            if(vis[i][reg])
            {
                flag=1;
                break;
            }
            else
            {
                vis[i][reg]=1;
            }
            if(ins[i].s[1]=='d')
            {
                reg=(reg+ins[i].v);
                ++i;
            }
            else if(ins[i].s[1]=='e')
            {
                if(ins[i].v==reg)
                    i=ins[i].k;
                else
                    ++i;
            }
            else if(ins[i].s[1]=='n')
            {
                if(ins[i].v!=reg)
                    i=ins[i].k;
                else
                    ++i;
            }
            else if(ins[i].s[1]=='l')
            {
                if(reg<ins[i].v)
                    i=ins[i].k;
                else
                    ++i;
            }
            else
            {
                if(reg>ins[i].v)
                    i=ins[i].k;
                else
                    ++i;
            }
        }
        if(flag)
            printf("No\n");
        else
            printf("Yes\n");
    }
    return 0;
}