比赛链接
T1
显然的贪心,按容量排序,每次选前 \(m\) 个组成木桶。
#include<bits/stdc++.h>
#define N 505
using namespace std;
int n,m,a[N*N];
int main(){int T;scanf("%d",&T);while(T--){long long ans=0;scanf("%d%d",&n,&m);for(int i=1;i<=n*m;i++) scanf("%d",a+i);sort(a+1,a+n*m+1);for(int i=1;i<=n*m;i+=m) ans+=a[i];printf("%lld\n",ans);}return 0;
}
T2
考虑枚举字串的位置,发现要覆盖的区间是内部的极小且包含全部 \(0\) 的段。
可以预处理每个点前面(包括自己)的第一个 \(0\) 的位置,分别对应代码中的 a,b 数组。
这样用 \(a_r-b_l\) 就可以求出区间 \([l,r]\) 的极小且包含全部 \(0\) 的段的长度,但当区间内没有 \(0\) 时会算出负数,所以最后答案要和 \(0\) 取 \(\max\)。
#include<bits/stdc++.h>
#define N 100005
using namespace std;
string s;int n,k,a[N],b[N];
int main(){int T;scanf("%d",&T);while(T--){int ans=INT_MAX;scanf("%d%d",&n,&k),cin>>s,k--;for(int i=n;i>=1;i--) s[i]=s[i-1]^48;for(int i=1;i<=n;i++) a[i]=s[i]?a[i-1]:i;for(int i=n;i>=1;i--) b[i]=s[i]?b[i+1]:i;for(int i=1;i<=n-k;i++) ans=min(ans,a[i+k]-b[i]+1>>1);printf("%d\n",max(ans,0));}return 0;
}
T4
枚举菱形的两个端点,那么它们形成的答案就是与这两个点距离等于它们的距离且连边平行的点对数。
可以将长度的平方(避免小数)和斜率(斜率相等则平行),为避免方位角的问题再存入所在以枚举的两个点为原点的象限,可以钦定大小顺序避免算重。
代码用的是 unordered_map 实现,被卡空间了,但个人认为比正确的代码更可读所以放上了。
#include<bits/stdc++.h>
#define N 2005
#define um unordered_map
using namespace std;
using ll=long long;
ll ans;
int n,x[N],y[N];
um<ll,vector<int>>a[N];
map<pair<pair<int,int>,pair<bool,bool>>,int>cnt;
int main(){scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d%d",x+i,y+i);for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(i^j)a[i][(ll)(x[i]-x[j])*(x[i]-x[j])+(ll)(y[i]-y[j])*(y[i]-y[j])].emplace_back(j);for(int i=1;i<n;i++) for(int j=i+1;j<=n;j++){ll len=(ll)(x[i]-x[j])*(x[i]-x[j])+(ll)(y[i]-y[j])*(y[i]-y[j]);vector<int>a1=a[i][len],a2=a[j][len];cnt.clear();for(auto p:a1){if(p>=j) break;int X=x[i]-x[p],Y=y[i]-y[p];int g=__gcd(X,Y);X/=g,Y/=g;cnt[{{X,Y},{x[i]<x[p],y[i]<y[p]}}]++;}for(auto p:a2){if(p>=i) break;int X=x[j]-x[p],Y=y[j]-y[p];int g=__gcd(X,Y);X/=g,Y/=g;ans+=cnt[{{X,Y},{x[j]<x[p],y[j]<y[p]}}];}}printf("%lld",ans);return 0;
}
