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 }
正解:其实我想的很贴近了==。两个操作杂糅一起的情况时,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 }
B. computer
考场:开始感觉题面晦涩难懂...手算了一下样例也对“随机选取”感到一头雾水...。于是跑去做了大模拟·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 }
正解:裸的最短路嘤嘤嘤。我们再来看这台计算机的计算过程:
- 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 }
小结:自己没看出来是最短路,还是太菜了...其实这个算法按这个描述还是很显然的啊(嘤)。还是要认真体会题目意思啊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 是变量,也不会对其进行修改。
考场:模拟啊...辰哥最强。感觉还是比较可做的,最后就是循环嵌套不会处理了,于是期望得分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 }
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 }
小结:还是模拟考虑的细节不够&码力太弱了嘤嘤嘤。
正解在博客园上显示不出来,我也很难受啊,贴链接
今天感觉海星..比前两天正睿考试的状态好些了...还会继续恢复的(本来就弱啊),今天题还是比较简单的,我分还是低啊(菜)。T3锅了20分就很难受了,还是细节真·重要啊qwq.而且最近好像一直没有在考场上A题了,是在专业打暴力233。其实有的时候思路和正解已经很贴近了,就差最后一步了,还是要多思考a(光速逃