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(光速逃

猜你喜欢

转载自www.cnblogs.com/nopartyfoucaodong/p/9823103.html