230927校内赛
T1 集合
题解
很明显的一道树形
我也没看出来
dalao们说有一道
于是都切了,就我是sb
首先有一个非常明显的性质在于所有的被选的点一定是可以构成一颗连通子树的
最终选取的 毛估估一下
于是可以用这条直径的端点情况与遍历的点的个数来设计状态
状态转移方程式见代码,不难理解的
直接
这样枚举一个点对时会在他们的
时间复杂度为
#include<bits/stdc++.h>
#define N 3010
using namespace std;
struct edge{
int v,ne,w;
}e[N<<1];
int n,k,cnt,ans,h[N],f[N][N],b[N][N],c[N][N],sz[N];
void add(int u,int v,int w){
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].ne = h[u];
h[u] = cnt;
}
void dp(int x,int fa){
sz[x] = 1;
f[x][1] = c[x][1] = b[x][1] = 0;
for(int i = h[x];i;i = e[i].ne){
int v = e[i].v;
if(v==fa) continue;
dp(v,x);
for(int y = sz[x];y>0;y--){
for(int j = sz[v];j>0;j--){
b[x][j+y] = min(b[x][j+y],b[v][j]+b[x][y]+e[i].w*2);
f[x][j+y] = min({f[x][j+y],b[v][j]+f[x][y]+e[i].w*2,
f[v][j]+b[x][y]+e[i].w});
c[x][j+y] = min({c[x][j+y],c[x][y]+b[v][j]+e[i].w*2,
c[v][j]+b[x][y]+e[i].w*2,f[x][y]+f[v][j]+e[i].w});
}
}
sz[x]+=sz[v];
}
ans = min({ans,c[x][k],b[x][k],f[x][k]});
}
signed main(){
freopen("set.in","r",stdin);
freopen("set.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
ans = 0x3f3f3f3f;
memset(f,0x3f,sizeof(f));
memset(c,0x3f,sizeof(c));
memset(b,0x3f,sizeof(b));
cin>>n>>k;
for(int i = 1;i<n;i++){
int x,y,w;
cin>>x>>y>>w;
add(x,y,w);add(y,x,w);
}
dp(1,0);
cout<<ans;
return 0;
}
日常讨厌
易水决
名字不错
题解
一道挺明显的贪心
有sb考试时侯想第一题去了放走了 100 分
首先思考单独对一个操作进行贪心
我们可以先给所有的
再将堆顶取出,将其再加上自身的时间后再放回去
这样进行
正确性?因为所有的都是放在堆里的,所以只要将最小的增加直到其不为最小一定是最优
对于
那么两个操作合并起来如何最大时间最小
将两个操作一个正序一个逆序拼接起来
不懂的可以看代码
正确性?对于两对操作来说,如果你要更换两个
时间复杂度因为有堆所以是
#include<bits/stdc++.h>
#define N 100010
#define int long long
using namespace std;
struct node{
int id,t;
bool operator <(node b)const{
return t>b.t;
}
};
int l,n,m,a[N],b[N],t[N*10];
signed main(){
freopen("farewell.in","r",stdin);
freopen("farewell.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>l>>n>>m;
for(int i = 1;i<=n;i++)
cin>>a[i];
for(int i = 1;i<=m;i++)
cin>>b[i];
priority_queue<node>p,q;
for(int i = 1;i<=n;i++)
q.push((node){i,a[i]});
for(int i = 1;i<=m;i++)
p.push((node){i,b[i]});
for(int i = 1;i<=l;i++){
int id = q.top().id,x = q.top().t;q.pop();
t[i] = x;
q.push((node){id,x+a[id]});
}
int ans = 0;
for(int i = l;i>0;i--){
int id = p.top().id,x = p.top().t;p.pop();
p.push((node){id,x+b[id]});
ans = max(ans,t[i]+x);
}
cout<<ans;
return 0;
}
T3 pockets
题解
对于两个区间的快速比较操作,通常会考虑到哈希操作,修改后就重新哈希一次
显然这么做的复杂度只适合于修改少询问多时
那么自然考虑到用线段树维护哈希
如果没有取模操作,那么数值只会变大
对于区间加操作,显然有区间哈希值增加
对于变
显然还是过不去的
需要优化的仍然是区间加操作
区间加有一个很简单的优化:差分!
比较时也可以用差分数组来比较
那么就只用单点修改并维护了
询问时不要忘了除了相同还要判断
区间哈希和这个新增加的条件都可以线段树维护
时间复杂度
#include<bits/stdc++.h>
#define N 500010
#define int unsigned long long
#define pii pair<int,int>
#define fi first
#define se second
using namespace std;
int n,q,mod,a[N],b[N];
pii pw[N],bas = {1331,233};
pii operator *(pii a,pii b){
return {1ll*a.fi*b.fi,1ll*a.se*b.se};
}
pii operator +(pii a,pii b){
return {a.fi+b.fi,a.se+b.se};
}
bool operator ==(pii a,pii b){
return a.fi==b.fi&&a.se==b.se;
}
struct node{
pii h;
int len;
node operator +(node b){
return (node){h*pw[b.len]+b.h,len+b.len};
}
bool operator ==(node b){
return h==b.h&&len==b.len;
}
};
struct seg{
#define lc (p<<1)
#define rc ((p<<1)|1)
#define mid ((l+r)>>1)
node t[N<<2];
int vl[N<<2];
void build(int p,int l,int r){
if(l==r){
vl[p] = b[l];
t[p] = (node){{b[l],b[l]},1};
return ;
}
build(lc,l,mid);
build(rc,mid+1,r);
t[p] = t[lc]+t[rc];
vl[p] = (vl[lc]+vl[rc])%mod;
}
node query(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return t[p];
if(qr<=mid) return query(lc,l,mid,ql,qr);
if(ql>mid) return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
int querysm(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return vl[p];
int res = 0;
if(ql<=mid) res = (res+querysm(lc,l,mid,ql,qr))%mod;
if(qr>mid) res = (res+querysm(rc,mid+1,r,ql,qr))%mod;
return res;
}
void update(int p,int l,int r,int v){
if(l==r){
vl[p] = b[l];
t[p] = (node){{b[l],b[l]},1};
return ;
}
if(v<=mid) update(lc,l,mid,v);
else update(rc,mid+1,r,v);
t[p] = t[lc]+t[rc];
vl[p] = (vl[lc]+vl[rc])%mod;
}
}T;
signed main(){
freopen("pockets.in","r",stdin);
freopen("pockets.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
pw[0] = {1,1};
for(int i = 1;i<N;i++) pw[i] = pw[i-1]*bas;
cin>>n>>q>>mod;
for(int i = 1;i<=n;i++){
cin>>a[i];
b[i] = (a[i]-a[i-1]+mod)%mod;
}
T.build(1,1,n);
while(q--){
int op,x,y,k;
cin>>op>>x>>y>>k;
if(op==1){
b[x] = (b[x]+k)%mod;
if(y<n) b[y+1] = (b[y+1]+mod-k)%mod;
T.update(1,1,n,x);
if(y<n) T.update(1,1,n,y+1);
}else{
int ok = 1;
if(T.querysm(1,1,n,x+1,y)!=0) ok = 0;
if(k>1)
if(!(T.query(1,1,n,x+1,x+k-1)==T.query(1,1,n,y+1,y+k-1)))
ok = 0;
if(ok) cout<<"ye5\n";
else cout<<"n0\n";
}
}
return 0;
}
T4 复制粘贴 3
我觉得洛谷的第三篇题解(写的是
#include<bits/stdc++.h>
#define int unsigned long long
#define inf 1e17
#define N 2510
using namespace std;
int n,a,b,c,tot,tk,pre[N][N],f[N][N],h[N],pw[N],p = 131;
string s;
unordered_map<int,int>mp;
void prework(){
pw[0] = 1;
for(int i = 1;i<=N-4;i++)
pw[i] = pw[i-1]*p;
for(int i = 1;i<=n;i++)
h[i] = (h[i-1]*p+(s[i-1]-'a'+1));
}
int gethash(int l,int r){
return (h[r]-h[l-1]*pw[r-l+1]);
}
signed main(){
freopen("copy.in","r",stdin);
freopen("copy.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>s>>a>>b>>c;
for(int i = 0;i<=n;i++)
for(int j = 0;j<=n;j++)
f[i][j] = inf;
prework();
for(int len = 1;len<=n;len++){
mp.clear();
for(int r = len;r<=n;r++){
int l = r-len+1;
if(l-len>=1) mp[gethash(l-len,l-1)] = l-len;
pre[l][r] = mp[gethash(l,r)];
}
}
for(int i = 1;i<=n;i++) f[i][i] = a;
for(int len = 1;len<n;len++){
for(int r = len;r<=n;r++){
int l = r-len+1;
f[l-1][r] = min(f[l-1][r],f[l][r]+a);
f[l][r+1] = min(f[l][r+1],f[l][r]+a);
int cc = 1,t = pre[l][r];
while(t){
cc++;
f[t][r] = min(f[t][r],f[l][r]+b+cc*c+(r-t+1-cc*len)*a);
t = pre[t][t+len-1];
}
}
}
cout<<f[1][n];
return 0;
}
梦与现实间挣扎着,所求为何
你可以借走我的文章,但你借不走我的智慧 虽然我是傻逼本文来自博客园,作者:cztq,转载请注明原文链接:https://www.cnblogs.com/cztq/p/17734344.html