@[TOC]
比赛试题
A 最短路
B 组队
题解:
先排序,然后二分查找比当前数a[i]大k的第一个数坐标是多少,假设坐标是j,那么j之后的都要比i大k,只有j之前,i之后的符合题意,i与j有j-i个数,求最大值
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+4; ll a[maxn]; int main() { int t; cin>>t; ll n,k; while(t--) { cin>>n>>k; for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+1+n); int sum=0; int ans=-1; for(int i=1;i<=n;i++) { sum=upper_bound(a+1,a+n+1,a[i]+k)-a; ans=max(ans,sum-i); } cout<<ans<<endl; } return 0; }
C 十面埋伏
我一开始想直接在#周围标记,然后输出就行,
发现会存在#围成密闭空间,那么空间里就不用围起来
我又发现围起来的部分都是最左边#的左边,最上边#的上边,最右边#的右边,最下边#的下边,样例1能过,但数据过不了一半,因为如果有深沟处理不了,如样例2
#include<bits/stdc++.h> using namespace std; char a[505][505]; int maxx[505],minn[505]; int main() { int n,m; cin>>n>>m; char ch=getchar(); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cin>>a[i][j]; } ch=getchar(); } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]=='#') { a[i][j-1]='*'; break; } } } for(int i=1;i<=n;i++) { for(int j=m;j>=1;j--) { if(a[i][j]=='#') { a[i][j+1]='*'; break; } } } for(int j=1;j<=m;j++) { for(int i=1;i<=n;i++) { if(a[i][j]=='#') { a[i-1][j]='*'; break; } } } for(int j=1;j<=m;j++) { for(int i=n;i>=1;i--) { if(a[i][j]=='#') { a[i+1][j]='*'; break; } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cout<<a[i][j]; } cout<<endl; } }
最后我才意识到,要把#周围全处理,其实直接dfs'.'
就是把圈外的'.'格dfs,然后标记,‘#’旁边被标记过的'.'格子就可以改成‘*’
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 505; int n,m; int dx[]={1,-1,0,0}; int dy[]={0,0,1,-1}; char a[maxn][maxn]; bool vis[maxn][maxn]; void dfs(int x,int y){ vis[x][y]=true; for(int i=0;i<4;i++){ int tx=x+dx[i]; int ty=y+dy[i]; if(vis[tx][ty]||tx<1||tx>n||ty<1||ty>m||a[tx][ty]!='.') continue; dfs(tx,ty); } } int main(){ cin>>n>>m; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ cin>>a[i][j]; } dfs(1,1); for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j]=='#') { for(int k=0;k<4;k++) { int tx=i+dx[k]; int ty=j+dy[k]; if(vis[tx][ty]) a[tx][ty]='*'; } } } } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { cout<<a[i][j]; } cout<<endl; } return 0; }
D 牛妹吃豆子
E 旅旅旅游
F 斗兽棋
大大大模拟。。
直接if比较就可以,因为这四个首字母不一样,直接首字母比较就可以。对了如果出的两个动物没有关系,也算平局
最后记住:舔狗一无所有!!!
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=2e5+4; string s1="tiangou txdy"; string s2="tiangou yiwusuoyou"; int main() { string w1,w2; cin>>w1>>w2; if(w1[0]=='e'&&w2[0]=='t')cout<<s2; else if(w1[0]=='t'&&w2[0]=='c')cout<<s2; else if(w1[0]=='c'&&w2[0]=='m')cout<<s2; else if(w1[0]=='m'&&w2[0]=='e')cout<<s2; else if(w2[0]=='e'&&w1[0]=='t')cout<<s1; else if(w2[0]=='t'&&w1[0]=='c')cout<<s1; else if(w2[0]=='c'&&w1[0]=='m')cout<<s1; else if(w2[0]=='m'&&w1[0]=='e')cout<<s1; else if(w1[0]=='e'&&w2[0]=='e')cout<<s2; else if(w1[0]=='t'&&w2[0]=='t')cout<<s2; else if(w1[0]=='c'&&w2[0]=='c')cout<<s2; else if(w1[0]=='m'&&w2[0]=='m')cout<<s2; else cout<<s2; return 0; }
G 做题
我一开还以为会存在性价比比较什么的,后来发现想多了。。
排个序从小开始算就完事了
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=5e5+4; int a[maxn]; int main() { long long n,m; scanf("%lld%lld",&n,&m); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); sort(a+1,a+1+n); int sum=0; for(int i=1;i<=n;i++) { if(m-a[i]>=0)sum++; else break; m-=a[i]; } printf("%lld",sum); return 0; }
H 人人都是好朋友
第一眼过去并查集,将有关的人联系在一起,判断时直接查询是否为父亲节点是否相同
注意a和b的范围远大于n,说明小弟不可能都登场,我们只需要小弟们的相对大小,即能区分开就行,所以离散化处理
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 5e6 + 3; int father[maxn]; int T; int a[maxn]; int b[maxn]; int c[maxn]; int d[maxn]; int n; bool f; int find(int x) { if(father[x]!=x)return father[x]=find(father[x]); else father[x]; } void lisanhua(int tot) { sort(d + 1, d + tot + 1); tot = unique(d + 1, d + tot + 1) - d; for (int i = 1; i <= n; i++) { a[i] = lower_bound(d + 1, d + tot + 1, a[i]) - d; b[i] = lower_bound(d + 1, d + tot + 1, b[i]) - d; } } void init(int tot) { for (int i = 1; i <= tot; i++)father[i] = i; } void unionn(int i) { father[find(a[i])]=find(b[i]); } bool iff(int i) { if(find(a[i])==find(b[i]))return 1; else return 0; } int main() { scanf("%d",&T); while (T--) { cin >> n; f = 1; int tot = 0; for (int i = 1; i <= n; i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); d[++tot] = a[i]; d[++tot] = b[i]; } lisanhua(tot);//离散化 init(tot);//初始化 for (int i = 1; i <= n; i++) { if (c[i])unionn(i); } for (int i = 1; i <= n; i++) { if (!c[i]) if(iff(i))f = 0; } if (f) cout<<"YES"; else cout<<"NO"; } return 0; }
I 求和
DFS序加线段树(或者树状数组)维护
代码略
J 建设道路
直接做n^2^肯定超时,需要优化,我们可以将公式一步步转化,最后转成O(n)
pre[]为a[i]的前缀和
pre1[]为a[i]^2^的前缀和
O(n)就可以算出
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; const int maxn=5e5+4; ll a[maxn]; ll pre[maxn]; ll pre1[maxn]; ll sum; ll ans1,ans2,ans3,ans; int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); pre[i]=(pre[i-1]+a[i])%mod; pre1[i]=(pre1[i-1]+a[i]*a[i])%mod; } for(int i=1;i<=n;i++) { ans1 = ((n - i) * ((a[i] * a[i]) % mod)) % mod; ans2 = ((2 * a[i]) % mod) * ((pre[n] - pre[i] + mod) % mod) % mod; ans3 = (pre1[n] - pre1[i]+mod) % mod; ans = (ans1 - ans2 + ans3+mod) % mod; sum=(sum+ans)%mod; } printf("%lld",sum); return 0; }
还有其他推法解法,但是我没看懂。。。我太弱了