10.11 上午 考试
T1
贪心的每次找最长的满足条件的序列,这样找到的一定是最少的
证明:
假如有更优的解,那么它在第一段一定是比贪心得出的第一段短一点,以此来满足后面的更少
但是这个序列的元素越少,越有可能构成等差数列,所以贪心一定是最优解
然后只需要判断相邻元素(不需要排序...)差的gcd==1和有没有相同元素
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <map>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=100006;
inline int abss(int x){return x<0?-x:x;}
int gcd(int x,int y){return y==0?x:gcd(y,x%y);}
int n;
int A[N];
map<int,int> mp;
int work()
{
int ans=1,num=0,gg;
for(int i=1;i<=n;++i)
{
if(mp.count(A[i]))
{
++ans;
mp.clear();
mp[A[i]]=1;
num=1;
continue;
}
mp[A[i]]=1;
++num;
if(num==1)continue;
if(num==2)
gg=abss(A[i]-A[i-1]);
else
gg=gcd(gg,abss(A[i]-A[i-1]));
if(gg==1)
{
++ans;
mp.clear();
mp[A[i]]=1;
num=1;
}
}
return ans;
}
int main(){
n=read();
for(int i=1;i<=n;++i)
A[i]=read();
cout<<work();
}
T2
暴力A题算法:
交:得到的跟原来的连边(单向的)
并:原来的跟得到的连边
k=1时是双向边...
然后从xdfs,能到y就行,标记不能用memset,时间戳即可
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=250006;
const int M=250006;
const int ALLK=500006;
struct son
{
int v,next;
}a1[3000006];
int first[3000006],e;
void addbian(int u,int v)
{
a1[e].v=v;
a1[e].next=first[u];
first[u]=e++;
}
int n,m,ccc;
int kk,op,tnum,tin1,tin2;
int ff;
int vis[N*3],tim;
inline void dfs(int x)
{
vis[x]=tim;
if(x==tin2)
{
ff=1;
return ;
}
for(int i=first[x];i!=-1;i=a1[i].next)
{
if(vis[a1[i].v]==tim)
continue;
dfs(a1[i].v);
}
}
int main(){
//freopen("T2.in","r",stdin);
mem(first,-1);
n=read();m=read();
ccc=n;
for(int i=1;i<=m;++i)
{
kk=read();
if(kk==0)
{
++ccc;
op=read();
tnum=read();
for(int j=1;j<=tnum;++j)
{
tin1=read();
if(tnum==1)
{
addbian(ccc,tin1);
addbian(tin1,ccc);
}
else
{
if(op==0)
addbian(ccc,tin1);
else
addbian(tin1,ccc);
}
}
}
else
{
tin1=read();tin2=read();
ff=0;++tim;
dfs(tin1);
printf("%d\n",ff);
}
}
}
正解是一个离线的算法,用dfs序
T3
有三种算法:
1.线段树(维护f[j]+B[j]和f[j]-sum[j])
直接维护区间最小值即可
2.线段树(维护f[j]+B[j]和一段区间[L,R] f[j]+$\sum_{k=j+1}^{L-1}$的最小值)
我考试时打的,可惜前两种算法在二分的时候我忘了对 i+k取min,结果i+K>n,然后就挂了...
3.正解:
维护两个堆:q一个维护f[j]+B[j],w一个维护f[j]-sum[j]
然后先往q里塞,取的时候先把i-j>K的扔掉,在把f[j]+B[j]<f[j]-sum[j]+sum[i]的塞进w里
再把f[i]对q和w取min
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline ll read()
{
char q=getchar();ll ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=1000006;
int n,K;
ll A[N],B[N];
ll pre[N];
ll INF;
ll f[N];
ll er(int now,int l,int r)
{
ll ans=INF;
int mid;
while(l<=r)
{
mid=(l+r)>>1;
if( pre[mid]-pre[now]>B[now]&&ans>mid )
ans=mid;
if(l>=r)
break;
if( pre[mid]-pre[now]>B[now] )
r=mid-1;
else
l=mid+1;
}
return ans;
}
struct TTTTTTTTTTTTTTTTTTTTTTTTTTTT__________________________TTTTTTTTTTTTTTTTTTTTTTTTTTTT
{
ll a[N*5],ji[N*5];
void clear(){mem(a,0x7f);mem(ji,0x7f);}
void pushup(int x){a[x]=(a[x<<1]<a[x<<1|1]?a[x<<1]:a[x<<1|1]);}
void pushdown(int x)
{
if(ji[x]!=INF)
{
ji[x<<1]=(ji[x<<1]<ji[x]?ji[x<<1]:ji[x]);
ji[x<<1|1]=(ji[x<<1|1]<ji[x]?ji[x<<1|1]:ji[x]);
a[x<<1]=(a[x<<1]<ji[x]?a[x<<1]:ji[x]);
a[x<<1|1]=(a[x<<1|1]<ji[x]?a[x<<1|1]:ji[x]);
ji[x]=INF;
}
}
void add(int L,int R,ll c,int l,int r,int x)
{
if(L>R)return ;
if(L<=l&&r<=R)
{
a[x]=(a[x]<c?a[x]:c);
ji[x]=(ji[x]<c?ji[x]:c);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)
add(L,R,c,l,mid,x<<1);
if(mid<R)
add(L,R,c,mid+1,r,x<<1|1);
pushup(x);
}
ll qq(int pos,int l,int r,int x)
{
if(l==r)
return a[x];
pushdown(x);
int mid=(l+r)>>1;
if(pos<=mid)
return qq(pos,l,mid,x<<1);
else
return qq(pos,mid+1,r,x<<1|1);
}
}T[2];
ll work()
{
mem(f,0x7f);f[0]=0;
INF=f[1];
ll tpos,tv,t1,t2;
T[0].clear();T[1].clear();
tpos=er(0,1,K);
if(tpos==INF)tpos=K+1;
T[0].add(1,tpos-1,f[0]+B[0],1,n,1);
T[1].add(tpos,min(K,n),f[0]-pre[0],1,n,1);
for(int i=1;i<=n;++i)
{
t1=T[0].qq(i,1,n,1);
t2=T[1].qq(i,1,n,1)+pre[i];
f[i]=(t1<t2?t1:t2);
tpos=er(i,i+1,std::min(i+K,n));
if(tpos==INF)tpos=i+K+1;
T[0].add(i+1,tpos-1,f[i]+B[i],1,n,1);
T[1].add(tpos,std::min(i+K,n),f[i]-pre[i],1,n,1);
}
return f[n];
}
int main(){
// freopen("T3.in","r",stdin);
// freopen("T3.out","w",stdout);
n=read();K=read();
for(int i=1;i<=n;++i)
{
A[i]=read();
pre[i]=pre[i-1]+A[i];
}
for(int i=0;i<n;++i)
B[i]=read();
cout<<work();
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline int read()
{
char q=getchar();int ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=1000006;
const int MAXK=100006;
int n,K;
int A[N],B[N];
ll f[N],pre[N];
ll INF;
ll er(int now,int l,int r)
{
ll ans=INF;
int mid;
while(l<=r)
{
mid=(l+r)>>1;
if( pre[mid]-pre[now]>B[now]&&ans>mid )
ans=mid;
if(l>=r)
break;
if( pre[mid]-pre[now]>B[now] )
r=mid-1;
else
l=mid+1;
}
return ans;
}
struct T_T
{
ll a[N*5],ji[N*5];
void clear()
{
mem(a,50);
mem(ji,50);
}
void pushup(int x)
{
a[x]=min(a[x<<1],a[x<<1|1]);
}
void pushdown(int x)
{
if(ji[x]!=INF)
{
ji[x<<1]=min(ji[x<<1],ji[x]);
ji[x<<1|1]=min(ji[x<<1|1],ji[x]);
a[x<<1]=min(a[x<<1],ji[x]);
a[x<<1|1]=min(a[x<<1|1],ji[x]);
ji[x]=INF;
}
}
void build(int l,int r,int x)
{
if(l==r)
{
a[x]=INF;
ji[x]=INF;
return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
void add(int L,int R,ll c,int l,int r,int x)
{
if(L>R)
return ;
if(L<=l&&r<=R)
{
ji[x]=min(ji[x],c);
a[x]=min(a[x],c);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(L<=mid)
add(L,R,c,l,mid,x<<1);
if(mid<R)
add(L,R,c,mid+1,r,x<<1|1);
pushup(x);
}
ll qq(int pos,int l,int r,int x)
{
if(l==r)
return a[x];
pushdown(x);
int mid=(l+r)>>1;
if(pos<=mid)
return qq(pos,l,mid,x<<1);
else
return qq(pos,mid+1,r,x<<1|1);
}
}T1;
struct TT_TT
{
ll a[N*5];
void clear()
{
mem(a,50);
}
void build(int l,int r,int x)
{
if(l==r)
{
a[x]=INF;
return ;
}
int mid=(l+r)>>1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
}
void add(int L,int R,ll c,int l,int r,int x)
{
//printf("T2add L=%d R=%d c=%lld l=%d r=%d x=%d\n",L,R,c,l,r,x);
if(L>R)
return ;
if(L<=l&&r<=R)
{
a[x]=min(a[x],c);
return ;
}
int mid=(l+r)>>1;
if(L<=mid)
add(L,min(R,mid),c,l,mid,x<<1);
if(mid<R)
{
ll ttt;
if(L>mid)
ttt=0;
else
ttt=pre[mid]-pre[L-1];
add(max(mid+1,L),R,c+ttt,mid+1,r,x<<1|1);
}
}
ll qq(int pos,int l,int r,int x)
{
if(l==r)
return a[x]+A[l];
int mid=(l+r)>>1;
ll ans=INF;
ans=min(ans,a[x]+pre[pos]-pre[l-1]);
if(pos<=mid)
ans=min(ans,qq(pos,l,mid,x<<1));
else
ans=min(ans,qq(pos,mid+1,r,x<<1|1));
return ans;
}
}T2;
void out11()
{
printf("\n");
for(int i=1;i<=n;++i)
printf("%lld ",T1.qq(i,1,n,1)==INF?-1:T1.qq(i,1,n,1));
printf("\n");
for(int i=1;i<=n;++i)
printf("%lld ",T2.qq(i,1,n,1)==INF?-1:T2.qq(i,1,n,1));
printf("\n");
}
void dp()
{
mem(f,50);
INF=f[0];
f[0]=0;
T1.clear();
T2.clear();
ll tpos;
ll t1,t2;
tpos=er(0,1,K);
if(tpos==INF)tpos=K+1;
T1.add(1,tpos-1,B[0],1,n,1);
T2.add(tpos,std::min(K,n),pre[tpos-1],1,n,1);
for(int i=1;i<=n;++i)
{
t1=T1.qq(i,1,n,1);
t2=T2.qq(i,1,n,1);
f[i]=(t1>t2?t2:t1);
tpos=er(i,i+1,std::min(i+K,n));
if(tpos==INF)tpos=i+K+1;
T1.add(i+1,tpos-1,f[i]+B[i],1,n,1);
T2.add(tpos,std::min(i+K,n),f[i]+pre[tpos-1]-pre[i],1,n,1);
//out11();
}
}
int main(){
//freopen("T3.in","r",stdin);
//freopen("T3.out","w",stdout);
n=read();K=read();
for(int i=1;i<=n;++i)
A[i]=read(),pre[i]=pre[i-1]+A[i];
for(int i=0;i<n;++i)
B[i]=read();
dp();
cout<<f[n];
/*printf("\n");
for(int i=1;i<=n;++i)
printf("%lld ",f[i]);
printf("\n");*/
}
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <queue>
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
inline ll read()
{
char q=getchar();ll ans=0;
while(q<'0'||q>'9')q=getchar();
while(q>='0'&&q<='9'){ans=ans*10+q-'0';q=getchar();}
return ans;
}
const int N=1000006;
struct son
{
int pos;
ll val;
son(){}
son(int _pos,ll _val){pos=_pos;val=_val;}
bool friend operator < (son a,son b)
{
return a.val>b.val;
}
};
int n,K;
ll A[N],B[N];
ll pre[N];
ll f[N];
priority_queue<son> q,w;
ll work()
{
mem(f,0x7f);
f[0]=0;
q.push( son(0,B[0]) );
son temp,t1,t2;
for(int i=1;i<=n;++i)
{
while(!q.empty())
{
temp=q.top();
if(i-temp.pos>K)
{
q.pop();
continue;
}
if(temp.val<f[temp.pos]-pre[temp.pos]+pre[i])
{
q.pop();
w.push( son(temp.pos,f[temp.pos]-pre[temp.pos]) );
continue;
}//printf("temp pos=%d val=%lld\n",temp.pos,temp.val);
break;
}
while(!w.empty()&&i-w.top().pos>K)
w.pop();
if(!q.empty())
{
//printf("q i=%d %lld\n",i,q.top().val);
f[i]=min(f[i],q.top().val);
}
if(!w.empty())
{
//printf("w i=%d %lld\n",i,w.top().val+pre[i]);
f[i]=min(f[i],w.top().val+pre[i]);
}
q.push( son(i,f[i]+B[i]) );
}
/*printf("\n");
for(int i=1;i<=n;++i)
printf("%lld ",f[i]);
printf("\n");*/
return f[n];
}
int main(){
// freopen("T3.in","r",stdin);
// freopen("T3.out","w",stdout);
n=read();K=read();
for(int i=1;i<=n;++i)
{
A[i]=read();
pre[i]=pre[i-1]+A[i];
}
for(int i=0;i<n;++i)
B[i]=read();
cout<<work();
}
什么?你问我为什么考这么渣、炸、扎
我能明天再说吗...