标签:
最近做的div2,很水的一次。
1)求最长不下降子序列。听说还要dp?这里的不下降子序列必须要求连续...所以水过
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <string> #include <queue> #include <vector> #include <stack> #include <set> #include <map> #include <algorithm> #include <ctime> #define ll long long #define maxn 1010 #define inf 0x7fffffff #define eps 1e-7 #define imax(x,y)(x>y)?x:y #define imin(x,y)(x<y)?x:y using namespace std; int n,ans=-1; int main() { scanf("%d",&n); int tmp=-1,cnt=0; for (int i=0;i<n;i++) { int now; scanf("%d",&now); if (now<tmp)cnt=0; cnt++;tmp=now; ans=imax(ans,cnt); } printf("%d",ans); return 0; }
2)从n个元素里选元素,每个元素有两个参数m,s,要求所选的所有元素中最大的元素的m于最小的元素的m相差小于d,求在这种限制条件下使得∑s最大,求这个最大值。
显然能选的都尽量选,也就是说最大值的m-最小值的m尽量接近d
排序然后两个指针,一个指向最小值,一个指向最大值,然后从小到大枚举最小值的时候,最大值的指针发现也是从小到大变化的,于是就可以O(n)求出每个元素作为最小值时候能得到的最大s。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <string> #include <queue> #include <vector> #include <stack> #include <set> #include <map> #include <algorithm> #include <ctime> #define ll long long #define maxn 100010 #define inf 0x7fffffff #define eps 1e-7 #define imax(x,y)(x>y)?x:y #define imin(x,y)(x<y)?x:y using namespace std; struct node { ll s,m; }t[maxn]; int n; ll d,s[maxn]; bool cmp(node a,node b) { return (a.m<b.m); } int main() { scanf("%d%lld",&n,&d); for (int i=0;i<n;i++)scanf("%lld%lld",&t[i].m,&t[i].s); sort(t,t+n,cmp); int j=0; s[0]=t[0].s; ll ans=0; for (int i=1;i<n;i++)s[i]=s[i-1]+t[i].s; for (int i=0;i<n;i++) if(i==0||t[i].m!=t[i-1].m) { ll tmp=0; while (j<n&&t[j].m<t[i].m+d)j++; if (i!=0)tmp=s[j-1]-s[i-1]; else tmp=s[j-1]; ans=imax(ans,tmp); } printf("%lld",ans); return 0; }
3)给你一个N个点的树,其中有一些是禁止点,现在要求你从根走到任意一个叶子节点,要求中途不能连续经过m个禁止节点,求满足这个条件下能走到多少个叶子节点。
特判为0的情况,然后写个bfs,写一个递推方程传递该点到根路径的最长连续禁止节点的个数就可以了。设con[i]为节点i到根节点的路上连续禁止节点的最大值,now[i]表示i为起点往根节点走,最多走连续多少禁止点,那么可以这样dp
如果i是禁止点,con[i]=max(now[father[i]]+1,con[father[i]]),now[i]=now[father[i]]+1,如果i不是禁止点,con[i]=con[father[i]]顺便now[i]=0,然后就可以了.
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <string> #include <queue> #include <vector> #include <stack> #include <set> #include <map> #include <algorithm> #include <ctime> #define ll long long #define maxn 100010 #define inf 0x7fffffff #define eps 1e-7 #define imax(x,y)(x>y)?x:y #define imin(x,y)(x<y)?x:y using namespace std; vector <int> e[maxn]; typedef vector<int>::iterator ii; int n,que[maxn],d,size[maxn],con[maxn]={ 0 },now[maxn]={ 0 },vis[maxn]={ 0 },lef[maxn]={ 0 }; void bfs() { int ls=0,rs=1; que[ls]=1;vis[1]=1; now[1]=con[1]=size[1]; while (ls!=rs) { int u=que[ls],siz=0; for (ii i=e[u].begin();i!=e[u].end();i++) { int v=*i;siz++; if (vis[v])continue; vis[v]=1; if (size[v]==0){ now[v]=0;con[v]=con[u];} else { now[v]=now[u]+1; con[v]=imax(con[u],now[v]); } que[rs]=v; rs++; } if (siz==1&&u!=1)lef[u]=1; ls++; } } int main() { scanf("%d%d",&n,&d); for (int i=1;i<=n;i++)scanf("%d",&size[i]); if (n==1) { int ans=0; if (size[1]<=d)ans++; printf("%d",ans); return 0; } for (int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); e[u].push_back(v); e[v].push_back(u); } bfs(); int ans=0; for (int i=1;i<=n;i++) if (lef[i]&&con[i]<=d)ans++; printf("%d",ans); return 0; }
4)给你一张完全带权有向图,要你任选一个点出发,走一长度为m的简单路径【同一个节点不能经过两次】,求最长路。
这题咱比赛的时候没写出来,为什么呢?因为咱看了看点数n=18,显然可能状态压缩dp下就可以了嘛,然后算了1<<18,然后没算出来就觉得:【啊,太大了,应该不是状压dp吧】【忘记了2^20才10^6...】
方法就是状压dp,用二进制表示当前选了哪些点,然后列个非常简单地dp方程就可以了。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <string> #include <queue> #include <vector> #include <stack> #include <set> #include <map> #include <algorithm> #include <ctime> #define ll long long #define maxn 1010 #define inf 0x7fffffff #define eps 1e-7 #define imax(x,y)(x>y)?x:y #define imin(x,y)(x<y)?x:y using namespace std; ll f[(1<<18)-1][19]={ 0 },g[20][20]={ 0 },c[20]; int n,m,k,dig[(1<<18)-1],pos[20]; int main() { scanf("%d%d%d",&n,&m,&k); for (int i=0;i<n;i++)scanf("%lld",&c[i]); for (int i=1;i<=k;i++) { int u,v;ll w; scanf("%d%d%lld",&u,&v,&w); g[u-1][v-1]=w; } pos[0]=1; for (int i=1;i<=n;i++)pos[i]=pos[i-1]<<1; for (int i=0;i<n;i++)dig[pos[i]]=1; for (int i=0;i<n;i++)f[pos[i]][i]=c[i]; ll ans=0; for (int i=1;i<pos[n];i++) { if ((i<<1)<pos[n])dig[i<<1]=dig[i]; if ((i<<1^1)<pos[n])dig[i<<1^1]=dig[i]+1; for (int j=0;j<n;j++) if ((i|pos[j])==i) { if (dig[i]!=1) for (int kk=0;kk<n;kk++) if (kk!=j&&(i|pos[kk])==i) f[i][j]=imax(f[i][j],f[i-pos[j]][kk]+c[j]+g[kk][j]); if (dig[i]==m) ans=imax(ans,f[i][j]); //printf("%d %d %lld\n",i,j,f[i][j]); } } //for (int i=1;i<pos[n];i++)printf("%d\n",dig[i]); printf("%lld",ans); return 0; }
5)给你一个字符串,两个操作:1)把区间[l,r]全部变成字符c 2)询问子串[l,r]是否是周期w的字符串,周期w意思是对于i∈[l,r-w],有 s[i]=s[i+w]
首先关于迅速判断(l,r)是否是周期w的字符串,s[l]=s[l+w],s[l+1]=s[l+1+w]...s[r-w]=s[r],所以可以直接转化为判断s[l,r-w]==s[l+w,r]?
其实问题就是询问两个字符串是否相等,这个可以用Hash来判断。而如果用Hash的话,显然可以建立一棵线段树,这样子就可以做区间变成c的操作了。
有几个注意的地方(r-l==w)的时候请特判,不然会死的很惨。
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <string> #include <queue> #include <vector> #include <stack> #include <set> #include <map> #include <algorithm> #include <ctime> #define ll long long #define maxn 100010 #define inf 0x7fffffff #define eps 1e-7 #define modd 1000000007 #define imax(x,y)(x>y)?x:y #define imin(x,y)(x<y)?x:y using namespace std; struct node { int a,b,l,r,sa,len; ll h; }t[maxn*2]; int n,m,k,tot=0; ll ans,now,ten[maxn],sav[10][maxn]; char a[maxn]; void maintain(int x) { if (t[x].l==0)return; t[x].h=t[t[x].l].h+t[t[x].r].h*ten[t[t[x].l].len]; if (t[x].h>=modd)t[x].h%=modd; } void push(int x) { if (t[x].sa==-1)return; if (t[x].l==0)return; t[t[x].l].sa=t[t[x].r].sa=t[x].sa; t[t[x].l].h=sav[t[x].sa][t[t[x].l].len]; t[t[x].r].h=sav[t[x].sa][t[t[x].r].len]; t[x].sa=-1; } int build(int l,int r) { int now=++tot; t[now].a=l;t[now].b=r;t[now].len=r-l;t[now].sa=-1; if (l+1<r) { int mid=(l+r)>>1; t[now].l=build(l,mid); t[now].r=build(mid,r); maintain(now); } else t[now].h=(a[l]-‘0‘); return now; } void change(int l,int r,int w,int x) { if(t[x].a>=l&&t[x].b<=r) { t[x].sa=w; t[x].h=sav[w][t[x].len]; push(x); return; } push(x); int mid=(t[x].a+t[x].b)>>1; if (mid>l)change(l,r,w,t[x].l); if (mid<r)change(l,r,w,t[x].r); maintain(x); } void query(int l,int r,int x) { if(t[x].a>=l&&t[x].b<=r) { ll tmp=(ten[now]*t[x].h); if (tmp>=modd)tmp%=modd; ans+=tmp; if (ans>=modd)ans%=modd; now+=t[x].len; return; } push(x); int mid=(t[x].a+t[x].b)>>1; if (mid>l)query(l,r,t[x].l); if (mid<r)query(l,r,t[x].r); maintain(x); } void prepare(int n) { for (int i=0;i<10;i++)sav[i][0]=0; for (int i=0;i<10;i++) for (int j=1;j<=n;j++) { sav[i][j]=sav[i][j-1]*10+i; if (sav[i][j]>=modd)sav[i][j]%=modd; } ten[0]=1;ll tt=10; for (int i=1;i<=n;i++) { ten[i]=ten[i-1]*tt; if (ten[i]>=modd)ten[i]%=modd; } } int main() { scanf("%d%d%d",&n,&m,&k); int q=m+k; scanf("%s",a); prepare(n); build(0,n); for (int i=0;i<q;i++) { int op,l,r,w; scanf("%d %d %d %d",&op,&l,&r,&w); if (op==1)change(l-1,r,w,1); if (op==2) { if (r==l||(r-l+1)==w){printf("YES\n");continue;} ans=now=0; query(l-1,r-w,1); ll h1=ans;ans=now=0; query(l+w-1,r,1); if (ans==h1)printf("YES\n");else printf("NO\n"); } } return 0; }
标签:
原文地址:http://www.cnblogs.com/z55250825/p/4847193.html