1. 程式人生 > >noi.ac 邀請賽1 By cellur925

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
4 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 }
期望的80

正解:其實我想的很貼近了==。兩個操作雜糅一起的情況時,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。接下來,這臺計算機的計算過程如下所述:

  1. 隨機選取一條連線線,設這條連線線是 i 號連線線;
  2. 隨機選取這條線的一端,設它為 x 號 CPU;
  3. 設這條線的另一端為 y 號 CPU;
  4. 設 t 為:x 號 CPU 上的值與 i 中較大的數;
  5. 如果 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=3B=AC=C。表示將變數修改為右側的值。
  • 加法語句:由變數、+=、值構成,例如 A+=9B+=B。表示將變數額外加上右側的值。
  • 語句:賦值語句、加法語句或者迴圈語句。
  • 迴圈語句:由 for(、變數、,、值、,、值、)、語句構成,例如 for(I,0,9)A+=Ifor(I,0,9)for(J,0,I)A+=J。設兩個值在此時依次為 a 和 b,則:
    • 所有的輸入資料保證此時 ab
    • 依次令變數取 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(光速逃