左手太顶了,369太9了,水子哥又成白开水了!!!
感觉还是难题做不了,水题做不快,都不知道怎么提升了。但先走下去吧,等一波奇迹团。
这次才做了7个,太菜了(还是在我360秘书的帮助下),剩下的看能力补。。。
题意大概就是给你n个三维的点,找离(0,0,0)最近的点的距离。for一遍。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int n; double ans=1e9+11; scanf("%d",&n); while(n--){ double x,y,z; scanf("%lf%lf%lf",&x,&y,&z); ans=min(ans,sqrt(x*x+y*y+z*z)); } printf("%.3f ",ans); return 0; }
A.Archmage
一开始有n>=x+y个mana,然后每秒会增加y个mana,并且每秒可以花费x个mana换1个Water Element,换操作是在增加操作之前的。问m秒后最多能有几个Water Element?
当x<=y,一直有mana课进行交换,x<y时,m-1秒增加的mana都有可能用上。
在m跟(n+(m-1)*y)/x取个最小值就好。
#include<bits/stdc++.h> using namespace std; typedef long long ll; int main(){ int t; scanf("%d",&t); while(t--){ ll n,m,x,y; scanf("%lld%lld%lld%lld",&n,&m,&x,&y); printf("%lld ",min(m,(n+(m-1)*y)/x)); } return 0; }
有m个可能重复的单词,笔记本最多记n个字符,每两个单词之间用一个空格隔开(会占用一个字符的位置),问最多记几个不一样的单词。
将单词按照长度,再按字典序排序,然后模拟即可。
这里发现个坑爹的地方,n=-1的时候,-1>=s[i].size()居然是true,不知道是为什么,希望有道友指点一下。
#include<bits/stdc++.h> using namespace std; typedef long long ll; string s[1011]; bool cmp(string a,string b){ return a.size()==b.size() ? a<b : a.size()<b.size(); } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=0;i<m;i++) cin>>s[i]; sort(s,s+m,cmp); int ans=0; for(int i=0;i<m;i++){ if(i&&s[i]==s[i-1]) continue; if(n>=s[i].size()){ ans++; n-=s[i].size(); }else break; n--; if(n<=0) break; } printf("%d ",ans); return 0; }
(这表情包我喜欢艹艹艹艹艹艹)
有n*m的草地,每个位置每秒会长aij的草,而在第t秒时,这个小熊会割掉一整行,或者一整列的草。问割了k次草后,小熊一共割了多少草。
一开始的想法复杂,但觉得可行也就直接敲了,没有往更简单的地方想。
我第一想法就是,时间从后往前,每一行每一列只会被割一次,那标记一下这一行和这一列有没有被割过就好。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=511,M=3e5+11; const ll md=998244353; char op[M][5]; bool visx[N],visy[N]; int pos[M]; ll a[N][N],xsum[N],ysum[N],tt[M]; int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%lld",&a[i][j]); a[i][j]%=md; xsum[i]+=a[i][j]; if(xsum[i]>=md) xsum[i]-=md; ysum[j]+=a[i][j]; if(ysum[j]>=md) ysum[j]-=md; } for(int i=0;i<k;i++) scanf("%s%d%lld",op[i],&pos[i],&tt[i]); ll ans=0; for(int i=k-1;i>=0;i--){ tt[i]%=md; if(op[i][0]=='r'){ if(visx[pos[i]]) continue; visx[pos[i]]=true; ans+=xsum[pos[i]]*tt[i]%md; xsum[pos[i]]=0; if(ans>=md) ans-=md; for(int j=1;j<=m;j++){ if(visy[j]) continue; ysum[j]-=a[pos[i]][j]; if(ysum[j]<0) ysum[j]=(ysum[j]%md+md)%md; if(ysum[j]==0) visy[j]=true; } }else{ if(visy[pos[i]]) continue; visy[pos[i]]=true; ans+=ysum[pos[i]]*tt[i]%md; ysum[pos[i]]=0; if(ans>=md) ans-=md; for(int j=1;j<=n;j++){ if(visx[j]) continue; xsum[j]-=a[j][pos[i]]; if(xsum[j]<0) xsum[j]=(xsum[j]%md+md)%md; if(xsum[j]==0) visx[j]=true; } } } printf("%lld ",ans); return 0; }
但由行列就可想到,某个位置,假如3秒被割了一次,5秒又被割了一次,那么直接视为5秒时割的就好。
有个坑就是,不能先对时间取模,先比了大小先再取模。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=511; const ll md=998244353; ll a[N][N],r[N],c[N]; int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ scanf("%lld",&a[i][j]); a[i][j]%=md; } char op[3]; int pos; ll tt; for(int i=0;i<k;i++){ scanf("%s%d%lld",op,&pos,&tt); if(op[0]=='r') r[pos]=tt; else c[pos]=tt; } ll ans=0; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ ans=(ans+max(r[i],c[j])%md*a[i][j]%md)%md; } printf("%lld ",ans); return 0; }
有1~n个点第i个点的权值就是斐波那契数第i项,m条边,每条的边权是两个点权和,问最小生成树中点的最大度数。
一开始也想复杂了,还想着二分找度数,但在判断它是不是最小生成树的时候就突然醒悟。
假设有a-b,c-d这两条边其中a<b,c<d,那么fib[a]+fib[b]!=fib[c]+fib[d],也就是任意两条边的边权不会相同。
因为假设b>=d+1,那么fib[b]>=fib[d]+fib[d-1],而c<=d-1,所以fib[a]+fib[b]>fib[c]+fib[d].
任意两条边的边权不会相同,那么最小生成树就只有一棵,直接求就行了。
#include<bits/stdc++.h> using namespace std; const int N=1e5+11; struct Side{ int u,v; bool operator<(Side &s1)const{ return v==s1.v ? u<s1.u : v<s1.v; } }S[N*2]; int n,m,fa[N],du[N]; int find(int x){ return fa[x]==x ? x : fa[x]=find(fa[x]); } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<m;i++){ scanf("%d%d",&S[i].u,&S[i].v); if(S[i].u>S[i].v) swap(S[i].u,S[i].v); } sort(S,S+m); for(int i=1;i<=n;i++) fa[i]=i,du[i]=0; int cnt=0,ans=0; for(int i=0;i<m;i++){ int u=S[i].u,v=S[i].v; int fu=find(u),fv=find(v); if(fu==fv) continue; cnt++; fa[fu]=fv; du[u]++;du[v]++; ans=max(ans,max(du[u],du[v])); if(cnt==n-1) break; } printf("%d ",ans); return 0; }
0~9每个数有c[i]个,问用这些数能组成的最大的4的倍数是什么。
一开始没啥思路,刚想换题,突然想起来4的倍数好像有个规律,然后就打表看了一下。
果不其然,4的倍数的规律就是2位数及以上的数最后两个数都是在某25个数之间循环的。
所以把这25个可能的最后2位数打出来,然后按照两个数的大小进行排序,让数小的在前面,然后枚举即可。
#include<bits/stdc++.h> using namespace std; int a[31]={ 0,20,12,32,40, 24,44,52,60,16, 36,64,56,72,76, 80,28,84,48,68, 88,92,96,}; int c[11],nd[11]; int main(){ int t; scanf("%d",&t); while(t--){ for(int i=0;i<=9;i++) scanf("%d",&c[i]); int flag=0; for(int i=0;i<23&&!flag;i++){ int x=a[i]/10,y=a[i]%10; nd[x]++;nd[y]++; if(c[x]>=nd[x]&&c[y]>=nd[y]){ flag=1; c[x]--;c[y]--; int pre0=1; for(int j=9;j>=0;j--){ if(c[j]){ if(j) pre0=0; if(!j&&pre0) continue; for(int k=0;k<c[j];k++) printf("%d",j); } } if(x||!pre0) printf("%d",x); printf("%d ",y); } nd[x]--;nd[y]--; } if(!flag){ if(c[8]) printf("8 "); else if(c[4]) printf("4 "); else if(c[0]) printf("0 "); else printf("-1 "); } } return 0; }
做了L就去吃东西了,看了一会比赛。。。然后回来傻逼的开了M,搞了快1个小时都没得。
最后看G过的多,去看了一眼,再让我360秘书帮忙翻译了一下。然后发现,啊,这波,这波是个水题。
题意里定义了一下函数,我就不说题意了。。。
设a[i]为以i为右边界的区间的答案,也就是题目中的A[i]=a[1]+a[2]+...+a[i]
每增加一个数bi+1,增加的区间就是[1,i+1],[2,i+1]...[i+1,i+1],
那么假设pos为bi+1左边第一个小于等于它的数的位置,那么bi+1作为最小值的区间也就是[pos+1,i+1],[pos+1,i+1]...[i+1,i+1]
而剩下的[1,i+1],[2,i+1]...[pos,i+1]由于bpos<bi+1,所以完全可以看出区间[1,pos],[2,pos]...[pos,pos]
也就是a[i]=b[i]*(i-pos)+a[pos],pos为i左边第一个小于等于b[i]的数的位置,可用单调栈求得。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e7+11; const ll md=998244353; stack<int> sta; ll a[N],b[N],ans[N]; int main(){ int n; ll p,x,y,z; scanf("%d%lld%lld%lld%lld%lld",&n,&p,&x,&y,&z,&b[1]); ans[1]=a[1]=b[1]; b[0]=-1; sta.push(0); sta.push(1); for(int i=2;i<=n;i++){ b[i]=(x*ans[i-1]%p+y*b[i-1]%p+z)%p; while(!sta.empty()&&b[sta.top()]>b[i]) sta.pop(); int pos=sta.top(); a[i]=(b[i]*(i-pos)%md+a[pos])%md; ans[i]=(ans[i-1]+a[i])%md; sta.push(i); } ll res=0; for(int i=1;i<=n;i++) res^=ans[i]; printf("%lld ",res); return 0; }