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;
}