noi.ac 邀請賽1 By cellur925
A. array
考場:上來就想暴力,首先第一個子任務肯定沒問題,怎麼搞都行。然後第二個子任務用個數組記下新修的值就行了。第三個子任務用一下等差數列求和公式幫助求解,每次都重新算(因為每次改變全部元素)。期望得分80分,實際得分40分。原因有2:快速乘不僅沒快,而且反而把我4個點搞TLE了....我再也不用手寫大整數乘法了;5~8測試點,說好的只有A型別,結果考後改了一個多小時都過不了子任務,後來在辰哥的指導下發現資料有鍋,5~8資料點藏著B型別的修改。我無fa♂可說。
1 #include<cstdio> 2 #include<algorithm> 3期望的804 using namespace std; 5 typedef long long ll; 6 7 ll n,m; 8 ll x,y; 9 ll ans; 10 char op[5]; 11 int seq[500]; 12 int a[50000090]; 13 bool vis[50000090]; 14 15 void re(ll &x) 16 { 17 x=0; 18 char ch=getchar(); 19 bool flag=false; 20 while(ch<'0'||ch>'9') flag|=(ch=='-'),ch=getchar(); 21 while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar(); 22 x=flag ? -x : x; 23 } 24 25 ll mul(ll a,ll b) 26 { 27 ll res=0; 28 while(b) 29 { 30 if(b&1) res=(res+a); 31 b>>=1; 32 a=a*2;33 } 34 return res; 35 } 36 37 void work1() 38 { 39 ll sta=n*(1+n)/2; 40 ans=x*sta+y*n; 41 printf("%lld\n",ans); 42 for(int i=2;i<=m;i++) 43 { 44 scanf("%s",op+1); 45 re(x);re(y); 46 ans=x*sta+y*n; 47 printf("%lld\n",ans); 48 } 49 } 50 51 void work2() 52 { 53 ll sta=mul(n,1+n); 54 sta>>=1; 55 ans=sta; 56 if(!vis[x]) 57 { 58 vis[x]=1; 59 ans-=x; 60 ans+=y; 61 a[x]=y; 62 } 63 printf("%lld\n",ans); 64 for(int i=2;i<=m;i++) 65 { 66 scanf("%s",op+1); 67 re(x);re(y); 68 if(!vis[x]) 69 { 70 vis[x]=1; 71 ans-=x; 72 ans+=y; 73 a[x]=y; 74 } 75 else 76 { 77 ans-=a[x]; 78 ans+=y; 79 a[x]=y; 80 } 81 printf("%lld\n",ans); 82 } 83 } 84 85 int main() 86 { 87 re(n);re(m); 88 if(n<=100) 89 { 90 for(int i=1;i<=n;i++) seq[i]=i,ans+=i; 91 for(int i=1;i<=m;i++) 92 { 93 scanf("%s",op+1); 94 re(x);re(y); 95 if(op[1]=='A') 96 { 97 ans=0; 98 for(int j=1;j<=n;j++) 99 seq[j]=j*x+y,ans+=seq[j]; 100 printf("%lld\n",ans); 101 } 102 else if(op[1]=='B') 103 { 104 ans-=seq[x]; 105 seq[x]=y; 106 ans+=y; 107 printf("%lld\n",ans); 108 } 109 } 110 return 0; 111 } 112 scanf("%s",op+1); 113 re(x);re(y); 114 if(op[1]=='A') work1(); 115 else if(op[1]=='B') work2(); 116 return 0; 117 }
正解:其實我想的很貼近了==。兩個操作雜糅一起的情況時,A操作不會受到B操作的影響,而B操作可能會受到A操作的影響。於是我們需要記錄一下之前的狀態。如果在這個B操作與上一個B操作之間存在一個A操作,那麼我們就不能無腦改值。記一個存新值的$seq$陣列,再記一個時間戳記錄狀態的$mar$陣列,我們就可以維護了。
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 5 using namespace std; 6 typedef long long ll; 7 8 int pos=1;//注意初始值為1!!!! 9 ll n,m; 10 ll x,y,px=1,py; 11 ll ans,sta; 12 char op[5]; 13 int seq[50000090]; 14 int mar[50000090]; 15 16 int main() 17 { 18 scanf("%lld%lld",&n,&m); 19 sta=(1+n)*n/2;ans=sta; 20 for(int i=1;i<=m;i++) 21 { 22 scanf("%s",op+1); 23 scanf("%lld%lld",&x,&y); 24 if(op[1]=='A') 25 { 26 pos++; 27 px=x,py=y; 28 ans=sta*x+y*n; 29 printf("%lld\n",ans); 30 } 31 else if(op[1]=='B') 32 { 33 if(mar[x]!=pos) ans=ans-(px*x+py)+y,mar[x]=pos; 34 else ans=ans-seq[x]+y; 35 seq[x]=y; 36 printf("%lld\n",ans); 37 } 38 } 39 return 0; 40 }AC
B. computer
題目描述
小 S 家裡有一臺奇怪的計算機……
這臺計算機中共有 n 顆 CPU。它們之間通過 m 條連線線相連,所有的 CPU 和連線線,分別用從 1 開始的連續正整數進行編號。
每一顆 CPU 上能夠儲存一個值。初始時,1 號 CPU 上的值為 0,而其他 CPU 的值均為 1e9。接下來,這臺計算機的計算過程如下所述:
- 隨機選取一條連線線,設這條連線線是 i 號連線線;
- 隨機選取這條線的一端,設它為 x 號 CPU;
- 設這條線的另一端為 y 號 CPU;
- 設 t 為:x 號 CPU 上的值與 i 中較大的數;
- 如果 t 比 y 號 CPU 上的值更小,則將 y 號 CPU 上的值改寫為 t。
計算機將重複上述過程,直到穩定:即無論在前兩步中如何選取,都無法在最後一步改寫任何 CPU 上的值。
你需要計算穩定狀態下所有 CPU 上的值。如果答案不唯一,你可以輸出任何一個解。
考場:開始感覺題面晦澀難懂...手算了一下樣例也對“隨機選取”感到一頭霧水...。於是跑去做了大模擬·T3。快結束的時候感覺不要掛題啊...於是逼著自己寫了一個奇怪的暴力,因為是重複上述過程直到穩定,所以可以亂搞一個“隨機演算法”,讓他跑2000次,目測能通過50%的資料,本來不抱希望的,結果我亂搞搞了最高的分數???
1 #include<cstdio> 2 #include<algorithm> 3 4 using namespace std; 5 6 int n,m; 7 int val[2000]; 8 struct node{ 9 int id,f,t; 10 }edge[100090]; 11 12 int main() 13 { 14 scanf("%d%d",&n,&m); 15 for(int i=1;i<=m;i++) 16 scanf("%d%d",&edge[i].f,&edge[i].t),edge[i].id=i; 17 for(int i=2;i<=n;i++) val[i]=1e9; 18 val[1]=0; 19 for(int T=1;T<=2000;T++) 20 { 21 for(int i=1;i<=m;i++) 22 { 23 int x=edge[i].f;int y=edge[i].t; 24 int t=max(i,val[x]); 25 if(t<val[y]) val[y]=t; 26 27 x=edge[i].t;y=edge[i].f; 28 t=max(i,val[x]); 29 if(t<val[y]) val[y]=t; 30 } 31 } 32 for(int i=1;i<=n;i++) printf("%d\n",val[i]); 33 return 0; 34 }50
正解:裸的最短路嚶嚶嚶。我們再來看這臺計算機的計算過程:
- 1號CPU值為0,其他CPU值為1e9--各個點的CPU值為dis陣列,即起點1到各個點的距離
- 如果t比y號CPU上的值更小,就把y號CPU上的值改為t--這不就是鬆弛過程嘛。於是我們發現各邊的邊權即為邊的編號。
所以我們直接跑一遍dij就行了,但是要注意,這裡更新就不是累加了,而是取最大值。
1 #include<cstdio> 2 #include<algorithm> 3 #include<queue> 4 #include<cstring> 5 #define maxn 100090 6 #define maxm 300090 7 8 using namespace std; 9 10 int n,m,tot; 11 int head[maxn],dis[maxn],vis[maxn]; 12 struct node{ 13 int to,next,val; 14 }edge[maxm*2]; 15 16 void add(int x,int y,int z) 17 { 18 edge[++tot].to=y; 19 edge[tot].next=head[x]; 20 head[x]=tot; 21 edge[tot].val=z; 22 } 23 24 void dijkstra() 25 { 26 priority_queue<pair<int,int> >q; 27 q.push(make_pair(0,1)); 28 for(int i=1;i<=n;i++) dis[i]=1e9; 29 dis[1]=0; 30 while(!q.empty()) 31 { 32 int u=q.top().second;q.pop(); 33 if(vis[u]) continue; 34 vis[u]=1; 35 for(int i=head[u];i;i=edge[i].next) 36 { 37 int v=edge[i].to; 38 int tmp=max(dis[u],edge[i].val); 39 if(dis[v]>tmp) 40 { 41 dis[v]=tmp; 42 q.push(make_pair(-dis[v],v)); 43 } 44 } 45 } 46 } 47 48 int main() 49 { 50 scanf("%d%d",&n,&m); 51 for(int i=1;i<=m;i++) 52 { 53 int x=0,y=0; 54 scanf("%d%d",&x,&y); 55 add(x,y,i);add(y,x,i); 56 } 57 dijkstra(); 58 for(int i=1;i<=n;i++) printf("%d\n",dis[i]); 59 return 0; 60 }AC
小結:自己沒看出來是最短路,還是太菜了...其實這個演算法按這個描述還是很顯然的啊(嚶)。還是要認真體會題目意思啊QAQ。
C. eval
題目描述
或許這道題比經典的“表示式求值”還是要簡單一點的。
有一種簡單的程式語言,我們如下定義其中的概念:
- 常數:單個數字,即
0
到9
。注意不會出現多位數字的情況。 - 變數:單個大寫字母,即
A
到Z
。每個變數可以儲存一個整數,所有變數的初始值為0
。 - 值:常數或者變數。
- 賦值語句:由變數、
=
、值構成,例如A=3
,B=A
,C=C
。表示將變數修改為右側的值。 - 加法語句:由變數、
+=
、值構成,例如A+=9
,B+=B
。表示將變數額外加上右側的值。 - 語句:賦值語句、加法語句或者迴圈語句。
- 迴圈語句:由
for(
、變數、,
、值、,
、值、)
、語句構成,例如for(I,0,9)A+=I
,for(I,0,9)for(J,0,I)A+=J
。設兩個值在此時依次為 a 和 b,則:- 所有的輸入資料保證此時 a≤b。
- 依次令變數取 a,a+1,a+2,…,b,計算右側的語句。
- 整個迴圈語句結束後,變數的值取 b。
- 右側的語句中,保證不會對迴圈變數進行修改(即不會出現在賦值語句和加法語句的左側,也不會成為另一個迴圈語句的變數),並且如果 a 和 b 是變數,也不會對其進行修改。
輸入格式
從標準輸入讀入資料。
輸入若干行,每行包含一個語句。你需要從上到下依次執行這些語句。
不會出現空格等無關字元。
輸出格式
輸出到標準輸出。
按照字母的順序,輸出所有不為 0 的變數。每行輸出一個,格式為:變數名、=
、它的值。如果值的位數超過了 9 位,則只輸出其最後 9 位,並在之前新增 ...
。
考場:模擬啊...辰哥最強。感覺還是比較可做的,最後就是迴圈巢狀不會處理了,於是期望得分60分。結果考後發現迴圈語句中的初值與末值也有可能是變數,於是跑了20分...難受。稽不如人肝敗下風而且最後的時候還好檢查了,少討論了一種變數為字母/數字的情況。而且還檢查出來掛檔案了qwq。
1 #include<cstdio> 2 #include<algorithm> 3 #include<map> 4 #include<cstring> 5 #include<cctype> 6 7 using namespace std; 8 9 int len,num[200],vis[1000]; 10 char fac[200]; 11 map<char,int>od; 12 13 int ksm(int a,int b) 14 { 15 int tmp=1; 16 while(b) 17 { 18 if(b&1) tmp=tmp*a; 19 b>>=1; 20 a=a*a; 21 } 22 return tmp; 23 } 24 25 int chang(int pos) 26 { 27 int tmp=0,lc=0; 28 for(int i=pos;i<=len;i++) num[i]=fac[i]-'0'; 29 for(int i=len;i>=pos;i--) 30 tmp+=ksm(10,lc)*num[i],lc++; 31 return tmp; 32 } 33 34 void output() 35 { 36 if(od['A']!=0) printf("A=%d\n",od['A']); 37 if(od['B']!=0) printf("B=%d\n",od['B']); 38 if(od['C']!=0) printf("C=%d\n",od['C']); 39 if(od['D']!=0) printf("D=%d\n",od['D']); 40 if(od['E']!=0) printf("E=%d\n",od['E']); 41 if(od['F']!=0) printf("F=%d\n",od['F']); 42 if(od['G']!=0) printf("G=%d\n",od['G']); 43 if(od['H']!=0) printf("H=%d\n",od['H']); 44 if(od['I']!=0) printf("I=%d\n",od['I']); 45 if(od['J']!=0) printf("J=%d\n",od['J']); 46 if(od['K']!=0) printf("K=%d\n",od['K']); 47 if(od['L']!=0) printf("L=%d\n",od['L']); 48 if(od['M']!=0) printf("M=%d\n",od['M']); 49 if(od['N']!=0) printf("N=%d\n",od['N']); 50 if(od['O']!=0) printf("O=%d\n",od['O']); 51 if(od['P']!=0) printf("P=%d\n",od['P']); 52 if(od['Q']!=0) printf("Q=%d\n",od['Q']); 53 if(od['R']!=0) printf("R=%d\n",od['R']); 54 if(od['S']!=0) printf("S=%d\n",od['S']); 55 if(od['T']!=0) printf("T=%d\n",od['T']); 56 if(od['U']!=0) printf("U=%d\n",od['U']); 57 if(od['V']!=0) printf("V=%d\n",od['V']); 58 if(od['W']!=0) printf("W=%d\n",od['W']); 59 if(od['X']!=0) printf("X=%d\n",od['X']); 60 if(od['Y']!=0) printf("Y=%d\n",od['Y']); 61 if(od['Z']!=0) printf("Z=%d\n",od['Z']); 62 } 63 64 int main() 65 { 66 while(scanf("%s",fac+1)!=EOF) 67 { 68 len=strlen(fac+1); 69 if(fac[1]!='f')// no cycle structures 70 { 71 if(fac[2]=='+') // add structures 72 { 73 char qwq=fac[1],qaq=fac[4]; 74 if(isdigit(fac[4])) od[qwq]+=chang(4);// add digit 75 else od[qwq]+=od[qaq];// add alpha 76 } 77 else // assignment structures 78 { 79 char qwq=fac[1]; 80 if(isdigit(fac[3])) od[qwq]=chang(3); 81 else od[qwq]=od[fac[3]]; 82 } 83 continue; 84 } 85 char qwq=fac[5]; 86 char qaq=fac[11]; 87 if(fac[12]=='+') // add with cycle 88 { 89 int cnt=(fac[9]-'0')-(fac[7]-'0')+1; 90 if(fac[len]==qwq) // add the same with cycle 91 { 92 int to=fac[9]-'0'; 93 int be=fac[7]-'0'; 94 od[qaq]+=(be+to)*cnt/2; 95 } 96 else 97 { 98 /*digit*/ if(isdigit(fac[len])) od[qaq]+=cnt*(fac[len]-'0'); 99 /*different*/ else od[qaq]+=cnt*od[fac[len]]; 100 } 101 } 102 else// assignment with cycle 103 { 104 if(fac[len]==qwq) 105 od[qaq]=fac[9]-'0'; 106 else 107 { 108 if(isdigit(fac[len])) od[qaq]=fac[len]-'0'; 109 else od[qaq]=od[fac[len]]; 110 } 111 } 112 od[qwq]=fac[9]-'0';// announce change 113 } 114 output(); 115 return 0; 116 }40
正解:參考了一下辰哥(tql%%%)的程式,發現我的程式寫的十分冗雜,許多字元和數字的轉化寫的都太麻煩了。而且迴圈巢狀那裡可以遞迴處理。感覺大模擬非常需要函數語言程式設計的思想啊(逃)。值得注意的一點,我們發現迴圈語句可能出現加自己的情況(參考樣例的最後一行),這樣結果就會變得巨大,甚至最大可能達到$2^1000000$。雖然題中沒有提到取膜,但是顯然longlong也承受不住的。因為最後大於9位的數字只輸出最後9位,所以我們可以取膜,但是不要改變最後的一系列數字就行了。注意儘量都開掉longlong,以及特殊的“...”處理用字元最好。
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 #include<iostream> 6 7 using namespace std; 8 typedef long long ll; 9 ll sjt=1000000000000; 10 ll cmp=2000000000000; 11 12 char tmp[20]; 13 ll tong[1000]; 14 char fac[200]; 15 16 void spj(int pos) 17 { 18 cout<<(char)(pos+'A')<<"="<<"..."; 19 ll st=tong[pos]; 20 for(int i=9;i>=1;i--) 21 tmp[i]=st%10+'0',st/=10; 22 for(int i=1;i<=9;i++) cout<<tmp[i]; 23 printf("\n"); 24 } 25 26 void output() 27 { 28 for(int i=0;i<=25;i++) 29 if(tong[i]) 30 { 31 if(tong[i]>=1000000000) spj(i); 32 else cout<<(char)(i+'A')<<"="<<tong[i]<<endl; 33 } 34 } 35 36 void cycle(ll pos); 37 38 void work(ll pos) 39 { 40 if(fac[pos]=='f') cycle(pos); 41 else 42 { 43 ll ch=fac[pos]-'A'; 44 if(fac[pos+1]=='+') 45 { 46 if(isdigit(fac[pos+3])) tong[ch]+=fac[pos+3]-'0'; 47 else tong[ch]+=tong[fac[pos+3]-'A']; 48 while(tong[ch]>cmp) tong[ch]-=sjt; 49 } 50 else 51 { 52 if(isdigit(fac[pos+2])) tong[ch]=fac[pos+2]-'0'; 53 else tong[ch]=tong[fac[pos+2]-'A']; 54 } 55 } 56 } 57 58 void cycle(ll pos) 59 { 60 ll ch=fac[pos+4]-'A'; 61 ll posl=pos+6,posr=pos+8,l=0,r=0; 62 if(isdigit(fac[posl])) l=fac[posl]-'0'; 63 else l=tong[fac[posl]-'A']; 64 if(isdigit(fac[posr])) r=fac[posr]-'0'; 65 else r=tong[fac[posr]-'A']; 66 for(ll i=l;i<=r;i++) 67 tong[ch]=i,work(pos+10); 68 while(tong[ch]>cmp) tong[ch]-=sjt; 69 } 70 71 int main() 72 { 73 while(scanf("%s",fac+1)!=EOF) 74 work(1); 75 output(); 76 return 0; 77 }AC
小結:還是模擬考慮的細節不夠&碼力太弱了嚶嚶嚶。
今天感覺海星..比前兩天正睿考試的狀態好些了...還會繼續恢復的(本來就弱啊),今天題還是比較簡單的,我分還是低啊(菜)。T3鍋了20分就很難受了,還是細節真·重要啊qwq.而且最近好像一直沒有在考場上A題了,是在專業打暴力233。其實有的時候思路和正解已經很貼近了,就差最後一步了,還是要多思考a(光速逃