\(1:10\) AK。
T1
注意到路线是从小的到大的点,因此可以从后往前确定。具体地说,确定一个点 \(i\),从前往后枚举 \(j>i\),如果现在到 \(j\) 的路线个数不符合奇偶性,就连一条边。
很容易证明是正确的。\(\mathcal{O}(N^3)\)。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 755;
int n;
char c[N][N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for (int i=1; i<n; i++){
for (int j=i+1; j<=n; j++){
cin>>c[i][j];
}
}
int ans=0;
for (int i=n-1; i>=1; i--){
vector<int> cnt(n+1,0);
for (int j=i+1; j<=n; j++){
if ((cnt[j]+(c[i][j]-'0'))&1){
ans++;
for (int k=j+1; k<=n; k++){
cnt[k]+=c[j][k]-'0';
}
}
}
}
cout<<ans<<endl;
return 0;
}
T2
首先,最长的路径长度非常好求(直接 topo sort)。要确保字典序最小,就要确定
-
第一个边的权值是可能中的最小的。
-
满足第一个条件后,所有路径当中去掉第一个边,字典序最小的。
发现解决最长路径为 \(d\) 的问题,转化成了如果能求出为 \(d-1\) 的所有点的最小字典序的 rank,就可以了。其次发现,topo sort 的时候一定是 \(d-1\) 在 \(d\) 前面。
因此就做完了。具体看代码。\(\mathcal{O}(N\log N)\)。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 4e5+5;
const int inf = 2e9;
int n,m,dis[N],in[N],rnk[N];
ll sum[N];
vector<pair<int,int> > g[N],rg[N];
pair<ll,ll> ans[N];
struct node {
int vl,rk,id;
bool operator < (const node &b) const {
return vl!=b.vl?vl<b.vl:rk<b.rk;
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>m;
for (int i=1; i<=m; i++){
int a,b,l;
cin>>a>>b>>l;
in[a]++;
rg[a].push_back({b,l});
g[b].push_back({a,l});
}
memset(dis,-1,sizeof dis);
int cur=0;
queue<int> q;
vector<node> v;
for (int i=1; i<=n; i++){
if (!in[i]){
dis[i]=0;
q.push(i);
}
}
while (!q.empty()){
int x=q.front();
q.pop();
if (cur!=dis[x]){
sort(v.begin(),v.end());
for (int i=0; i<v.size(); i++){
rnk[v[i].id]=i;
}
v.clear();
cur=dis[x];
}
node it={inf,inf,x};
ll mx=0,psum=0;
for (auto p : rg[x]){
int y=p.first,l=p.second;
node itt={l,rnk[y],x};
if (itt<it&&mx==dis[y]+1 || mx<dis[y]+1){
psum=sum[y]+l;
mx=dis[y]+1;
it=itt;
}
}
ans[x]={mx,psum};
sum[x]=psum;
v.push_back(it);
for (auto p : g[x]){
int y=p.first,l=p.second;
in[y]--;
if (!in[y]){
dis[y]=dis[x]+1;
q.push(y);
}
}
}
for (int i=1; i<=n; i++){
cout<<ans[i].first<<" "<<ans[i].second<<"\n";
}
return 0;
}
听说有 hash 的做法,但是不会。
T3
先给出一个离线的 \(\mathcal{O}(N\log N)\) 的做法。
离线下来,按照 \(\frac{a}{b}\) 从大到小排序。很容易得知,出发的位置是按照排序越来越大的。
根据人类智慧,是单谷函数,因此可以直接维护一个东西从左往右扫。
Code
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e6+6;
struct qy {
ll a,b;
int id;
bool operator < (const qy &x) const {
// a/b>x.a/x.b
return a*x.b>x.a*b;
}
} qs[N];
ll n,q,x[N],vis[N];
ll lf[N],ri[N],ans[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for (int i=1; i<=n; i++){
cin>>x[i];
vis[x[i]]++;
}
ll cnt=0;
for (int i=0; i<N; i++){
lf[i]=(i==0?0:lf[i-1])+cnt;
cnt+=vis[i];
}
cnt=0;
for (int i=N-2; i>=0; i--){
ri[i]=ri[i+1]+cnt;
cnt+=vis[i];
}
cin>>q;
for (int i=1; i<=q; i++){
cin>>qs[i].a>>qs[i].b;
qs[i].id=i;
}
sort(qs+1,qs+1+q);
ll cur=0;
for (int i=1; i<=q; i++){
ll a=qs[i].a,b=qs[i].b;
#define cal(x) (a*lf[x]+b*ri[x])
while (cal(cur)>cal(cur+1)){
cur++;
}
ans[qs[i].id]=cal(cur);
}
for (int i=1; i<=q; i++){
cout<<ans[i]<<"\n";
}
return 0;
}
因为单谷,所以在线做法就是三分。
听说有都少掉一个 \(\log\) 的,很想学。
标签:qs,const,int,ll,USACO,long,2023,using,Dec From: https://www.cnblogs.com/SFlyer/p/17909166.html