USACO26FIRST总结
Bronze
T1
贪心去构造
分 \(cb \le ca\) 和 \(cb > ca\) 的情况讨论
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
typedef long long ll;
const int N = 2e5+10;
ll A,B,ca,cb,gt;
void work(){
cin>>A>>B>>ca>>cb>>gt;
ll now = A+(B/cb*ca);
if (now >= gt){cout << "0\n"; return ;}
ll rm = cb - (B%cb), ans = 0;
if (cb <= ca){
ans = gt-now+rm-1;
} else {
if ((gt-now)%ca == 0) ans = max(rm-1+gt-now, rm-1+(gt-now-ca)/ca*cb+ca);
else ans = max(rm-1+gt-now, rm-1+(gt-now)/ca*cb+(gt-now)%ca);
}
cout << ans << "\n";
}
int main(){
int _; cin >> _;
while (_--) work();
return 0;
}
/*
1 0 2 3 5
*/
T2
构造题,判掉 \(n\) 为奇数的情况,首先发现答案 \(\le 3\),判掉答案为 \(1\) 的情况,考虑怎样可以使答案 \(= 2\),我们将字符串三个为一组,整个字符串中间劈开,那么要求左边和右边分成两部分,分别相同,每三个字符构造即可,最终发现答案最多为 \(2\)
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
typedef long long ll;
const int N = 1e5+10;
int n,k;
char cs[4];
string s;
struct D{
int x,y,z;
} op[4][4],ans[N];
int chk(string x){
if (x == "COW") return 1;
if (x == "OWC") return 2;
if (x == "WCO") return 3;
return 0;
}
void work(){
cin >> n;
cin >> s;
s = " "+s;
if (n&1){
cout << "-1\n";
return ;
}
if (s.substr(1,n*3/2)==s.substr(n*3/2+1,n*3/2)){
cout << "1\n";
F(i,1,n*3-1) cout << "1 ";
cout << "1\n";
return ;
}
F(i,1,n/2){
int a = chk(s.substr(i*3-2,3)), b = chk(s.substr(i*3-2+n*3/2,3));
ans[i] = op[a][b], ans[i+n/2] = op[b][a];
}
cout << "2\n";
F(i,1,n){
cout<<ans[i].x<<" "<<ans[i].y<<" "<<ans[i].z;
if (i!=n) cout<<" ";
}
cout << "\n";
}
int main(){
op[1][1] = {1,1,2}, op[1][2] = {2,1,1}, op[1][3] = {1,1,2};
op[2][1] = {1,1,2}, op[2][2] = {1,1,2}, op[2][3] = {2,1,1};
op[3][1] = {2,1,1}, op[3][2] = {1,1,2}, op[3][3] = {1,1,2};
int _; cin >> _ >> k;
while (_--) work();
return 0;
}
/*
1 0 2 3 5
COW OWC WCO
COW WCO COW | OWC COW OWC
11 1 11 1 1 1 1
COWCOWOWC OWCOWCOWC
*/
T3
注意到 \(k\) 较小,且每次更新的位置一定增加,只需维护被更新的矩形即可
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
typedef long long ll;
const int N = 5e2+10;
int n,k,q;
ll ma[N][N],ar[N][N],ans;
int main(){
cin >> n >> k >> q;
while (q--){
int r,c; ll v;
cin >> r >> c >> v;
F(i,max(1,r-k+1),r){
F(j,max(1,c-k+1),c){
ma[i][j] += v-ar[r][c];
ans = max(ans,ma[i][j]);
}
}
ar[r][c] = v;
cout << ans << "\n";
}
return 0;
}
/*
1 0 2 3 5
*/
Silver
打表出来,观察规律
对于第一个询问,可以直接维护这个数的移动,类似倍增
对于第二个询问,我们首先转化为某个时间位置 \(1\) 的数,那么我们从 \(t\) 时间倒推回去,观察发现当 \(t \mod 3 = 2\) 时,\(1\) 位置的数是 \(\large \frac{t+1}{3}\),于是每次将 \(t\) 缩小
T1
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i = a; i <= b; i++)
#define F_(i,a,b) for(int i = a; i >= b; i--)
#define pii pair<int,int>
#define fr first
#define sc second
#define mem0(a) memset(a,0,sizeof(a))
#define pb push_back
#define lb(x) (x&(-x))
#define lson u<<1
#define rson u<<1|1
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e5+10,M = 1e4+2;
const double eps = 1e-5;
const ll Mod = 1e9+7;
// huangyuze
int q;
ll solve1(ll x,ll t){
if (x*2-1 >= t) return x;
t -= x*2-1;
ll pos = x, nowt = x*2-1;
while (t){
if (pos-t >= 0){
pos -= t;
t = 0;
break;
}
t -= pos+1;
nowt += pos+1;
pos = nowt/2;
}
return pos;
}
ll solve2(ll x,ll t){
if (x >= t/2+1) return x;
t += x;
while (t%3!=2 && t){
if ((t-1)%3 == 0) t = t*2/3;
else t = (t*2-1)/3;
}
return (t+1)/3;
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cin >> q;
while (q--){
int op; ll x,t;
cin >> op >> x >> t;
if (op == 1) cout << solve1(x,t) << "\n";
else cout << solve2(x,t) << "\n";
}
return 0;
}
T2
将 \(x,y\) 之间连边,形成若干的连通块,对于每个连通块考虑
若出现环,分奇环和偶环考虑
若一个连通块内有一个数的值确定,那么整个连通块可以确定
否则,可以看成树考虑,那么我们把每个限制用不等式表示化简,形成若干个区间,那么就相当于找到一个点,覆盖最多区间,排序+树状数组即可
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
#define F_(i,a,b) for(int i=a; i>=b; --i)
#define FG(u,i) for(int i=final[u]; i; i=edge[i].pre)
#define pii pair<int,int>
#define pll pair<long long,long long>
#define fr first
#define sc second
#define pb push_back
typedef long long ll;
const int N = 2e5+10; const ll MA = 1e18;
int n,m,dep[N],rtf,ans;
ll ps[N][2];
ll L[N],R[N],val[N],hs[N],lhs;
bool wj,visb[N],visf[N],nson[N];
struct EDGE{int to,pre; ll len;} edge[N*2];
int final[N],ec;
struct E{int u,v; ll w;};
vector<E> fze; vector<int> vt;
map<pii,ll> mp;
struct BIT{
int val[N];
void init(){F(i,1,lhs) val[i] = 0;}
void add(int p){for (int i=p; i<=lhs; i+=(i&-i)){++val[i];}}
int qry(int p){int res = 0; for (int i=p; i>=1; i-=(i&-i)){res += val[i];} return res;}
} T;
void add(int u,int v,ll w){
edge[++ec] = {v,final[u],w};
final[u] = ec;
}
void dfsf(int u,int fu){
visf[u] = 1;
FG(u,i){
int v = edge[i].to; ll w = edge[i].len;
fze.pb({u,v,w});
if (visf[v]) continue;
if (val[v]!=MA && val[v]!=w-val[u]) wj=1;
val[v] = w-val[u];
dfsf(v,u);
}
}
void chkf(int u){
fze.clear(); dfsf(u,0);
for (auto [u,v,w]:fze){
if (val[u]+val[v] != w) wj=1;
}
}
void dfsb(int u,int fu){
vt.pb(u); dep[u] = dep[fu]+1; visb[u] = 1;
FG(u,i){
int v = edge[i].to;
if (visb[v]){nson[v]=(v!=fu); continue;}
ps[v][0]=ps[u][0], ps[v][1]=ps[u][1];
ps[v][(dep[u]+1)&1] += edge[i].len;
dfsb(v,u);
}
FG(u,i){
int v = edge[i].to; ll w = edge[i].len;
if (nson[v]&&dep[u]<dep[v]){
int o = dep[v]&1;
ll csb = (ps[v][o]-ps[u][o]+ps[u][!o]-ps[v][!o]), k = (dep[v]-dep[u]+1)&1;
if (!k){
if (csb != w) wj=1;
} else {
if ((w-csb)%2==1) wj=1;
else {
if (val[u]!=MA&&val[u]!=(w-csb)/2) wj=1;
else val[u] = (w-csb)/2, rtf = u;
}
}
}
}
}
inline int Z(ll x){
return lower_bound(hs+1,hs+lhs+1,x)-hs;
}
void solve(){
vector<pll> seg;
F(i,0,(int)vt.size()-1){
int u = vt[i], o = dep[u]&1;
ll csb = ps[u][o]-ps[u][!o];
if (o) seg.pb({L[u]-csb,R[u]-csb});
else seg.pb({csb-R[u],csb-L[u]});
}
sort(seg.begin(),seg.end());
F(i,1,seg.size()) hs[i] = seg[i-1].sc;
sort(hs+1,hs+seg.size()+1); lhs = unique(hs+1,hs+seg.size()+1)-hs-1;
int sum = 0;
for (auto [l,r]:seg){
T.add(Z(r));
sum = max(sum,T.qry(lhs)-T.qry(Z(l)-1));
}
T.init();
ans += sum;
}
void init(){
mp.clear();
wj = 0; ans = 0;
F(i,1,n) visf[i]=visb[i]=nson[i]=0;
F(i,1,n) ps[i][0]=ps[i][1]=dep[i]=0;
ec = 0;
F(i,1,n) final[i] = 0;
}
void work(){
init();
cin >> n >> m;
F(i,1,n) cin >> L[i];
F(i,1,n) cin >> R[i];
F(i,1,n) val[i] = MA;
F(i,1,m){
int u,v; ll w;
cin >> u >> v >> w;
if (mp.count({u,v})){
if (mp[{u,v}] != w) wj = 1;
continue;
}
if (u==v){
if (w&1) wj = 1;
else val[u] = w/2;
} else {
add(u,v,w); add(v,u,w);
}
mp[{u,v}] = mp[{v,u}] = w;
}
F(i,1,n){
if (val[i]!=MA&&!visf[i]){
dfsf(i,0);
}
}
F(i,1,n){
if (!visf[i]&&!visb[i]){
vt.clear(); rtf=0; dfsb(i,0);
if (rtf) chkf(rtf);
else solve();
}
}
if (wj){cout<<"-1\n";return;}
F(i,1,n) if (L[i]<=val[i] && val[i]<=R[i]) ++ans;
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _; cin >> _;
while (_--) work();
return 0;
}
T3
将相邻两个 \(s\) 相减,发现是 \(b_i\) 和 \(b_{i+k}\) 的关系,那么枚举余数考虑
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i=a; i<=b; ++i)
typedef long long ll;
const int N = 2e5+10;
int n,k,sum[2];
string s;
int val[N],ma[N][2],mi[N][2];
void work(){
cin >> n >> k;
cin >> s; s = " "+s;
F(i,1,n-k) val[i] = (s[i+1]-s[i]+2)%2;
F(i,1,k) F(o,0,1) ma[i][o]=mi[i][o]=0;
ma[0][1]=-1e9, mi[0][1]=1e9;
F(r,1,k){
sum[0]=0, sum[1]=1;
F(fr,0,1){
int lst = fr;
for (int i=r+k; i<=n; i+=k){
if (lst^val[i-k]) ++sum[fr];
lst ^= val[i-k];
}
}
ma[r][0] = max(ma[r-1][0]+sum[0],ma[r-1][1]+sum[1]);
ma[r][1] = max(ma[r-1][1]+sum[0],ma[r-1][0]+sum[1]);
mi[r][0] = min(mi[r-1][0]+sum[0],mi[r-1][1]+sum[1]);
mi[r][1] = min(mi[r-1][1]+sum[0],mi[r-1][0]+sum[1]);
}
cout<<mi[k][s[1]-'0']<<" "<<ma[k][s[1]-'0']<<"\n";
}
int main(){
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _; cin >> _;
while (_--) work();
return 0;
}
/*
1 0 2 3 5
*/
Gold
T3
dp 的优化
首先容易想到 \(dp_{i,j}\) 表示前 \(i\) 个人中最后一个教练为 \(j\) 的方案数,然后发现 \(i\) 没用,变成 \(dp_i\) 表示最后一个教练为 \(i\) 的方案数,那么枚举上一个教练转移,贡献为 \(2\) 的幂,然后就是化简式子前缀和加二分计算即可
#include <bits/stdc++.h>
using namespace std;
#define F(i,a,b) for(int i = a; i <= b; i++)
#define F_(i,a,b) for(int i = a; i >= b; i--)
#define pii pair<int,int>
#define fr first
#define sc second
#define mem0(a) memset(a,0,sizeof(a))
#define pb push_back
#define lb(x) (x&(-x))
#define lson u<<1
#define rson u<<1|1
typedef long long ll;
typedef unsigned long long ull;
const int N = 1e6+10,M = 1e4+2;
const double eps = 1e-5;
const ll Mod = 1e9+7, ny2 = (Mod+1)/2;
// huangyuze
int n,md,sch[N];
ll dtp[N],dto[N];
ll dp[N],ans,pw2[N],inv2[N],S2[N],S3[N];
inline void add(ll &a,ll b){
a = (a+b%Mod+Mod)%Mod;
}
int main(){
cin >> n >> md;
F(i,1,n) cin >> dtp[i] >> dto[i];
F(i,1,n) sch[i] = sch[i-1]+dto[i];
pw2[0] = 1;
F(i,1,n) pw2[i] = pw2[i-1]*2%Mod;
inv2[0] = 1;
F(i,1,n) inv2[i] = inv2[i-1]*ny2%Mod;
dtp[n+1] = 1e18, dto[n+1] = 1;
F(i,1,n+1){
if (dto[i]){
if (i!=n+1) dp[i] = 1;
int pos = lower_bound(dtp+1,dtp+i+1,dtp[i]-md)-dtp-1;
add(dp[i],S3[pos]);
add(dp[i],pw2[i-sch[i]]*(S2[i-1]-S2[pos]));
}
add(S2[i],S2[i-1] + dp[i]*inv2[i-sch[i]]);
int pi = upper_bound(dtp+i,dtp+n+1,dtp[i]+md)-dtp-1;
add(S3[i],S3[i-1] + dp[i]*pw2[pi-i-sch[pi]+sch[i]]);
}
cout << dp[n+1];
return 0;
}

浙公网安备 33010602011771号