CodeForces Round 321 div 2

最近做的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;
}

a.cpp

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;
}

b.cpp

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;
}

c.cpp

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;
}

d.cpp

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;
}

e.cpp

时间: 2024-12-21 19:56:41

CodeForces Round 321 div 2的相关文章

codeforces水题100道 第十四题 Codeforces Round #321 (Div. 2) A. Kefa and First Steps (brute force)

题目链接:http://www.codeforces.com/problemset/problem/580/A题意:求最长连续非降子序列的长度.C++代码: #include <iostream> using namespace std; const int maxn = 100100; int n, a[maxn], tmp, ans; int main() { cin >> n; for (int i = 0; i < n; i ++) cin >> a[i]

Codeforces Round #321 (Div. 2) D. Kefa and Dishes (状压dp,再A一发)

题意: 有n个菜,需要m个菜,k个规则  每个菜吃下去的满足感为 a1......an 每个规则: 吃完第u个菜后吃第v个菜满足感+c; 问:怎么吃才能幸福感最大? dp[1<<18][20]:一维表示吃了的菜(1表示吃了,0表吃没吃),第二维表示最后一个吃的菜 dp的初始化: dp[1<<i][i] = saty[i]; 状态转移:dp[i|(1 << k)][k] = max(dp[i][j] + rule[j][k] + safy[k],dp[i|(1 <&

Codeforces Round #321 (Div. 2) A, B, C, D, E

580A. Kefa and First Steps 题目链接: A. Kefa and First Steps 题意描述: 给出一个序列,求最长公共子序列多长? 解题思路: 水题,签到 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 int main () 8 { 9 in

Codeforces Round #321 (Div. 2) Kefa and Park 深搜

原题链接: 题意: 给你一棵有根树,某些节点的权值是1,其他的是0,问你从根到叶子节点的权值和不超过m的路径有多少条. 题解: 直接dfs一下就好了. 代码: #include<iostream> #include<cstring> #include<vector> #include<algorithm> #define MAX_N 100005 using namespace std; vector<int> G[MAX_N]; int n,m

Codeforces Round #321 (Div. 2) D Kefa and Dishes

用spfa,和dp是一样的.转移只和最后一个吃的dish和吃了哪些有关. 把松弛改成变长.因为是DAG,所以一定没环.状态最多有84934656,514ms跑过,cf机子就是快. #include<bits/stdc++.h> using namespace std; typedef pair<int,int> nd; typedef long long ll; #define fi first #define se second int n,m,a[18]; int g[18][

Codeforces Round #321 (Div. 2) C Kefa and Park

dfs一遍,维护当前连续遇到的喵的数量,然后剪枝,每个统计孩子数量判断是不是叶子结点. #include<bits/stdc++.h> using namespace std; const int maxn = 2e5+5; int a[maxn]; int head[maxn],nxt[maxn<<1],to[maxn<<1],ect; inline void addEdge(int u,int v) { to[ect] = v; nxt[ect] = head[u]

Codeforces Round #321 (Div. 2) B. Kefa and Company

排序以后O(n)枚举尾部.头部单调,维护一下就好. #include<bits/stdc++.h> using namespace std; typedef long long ll; //#define LOCAL const int maxn = 1e5+5; struct Node { int m,s; void IN(){ scanf("%d%d",&m,&s); } bool operator < (const Node&rh) co

2017-5-6-Train:Codeforces Round #321 (Div. 2)

A. Kefa and First Steps(最长不下降子串) Kefa decided to make some money doing business on the Internet for exactly n days. He knows that on the i-th day (1 ≤ i ≤ n) he makes a**i money. Kefa loves progress, that's why he wants to know the length of the maxi

Codeforces Round #321 (Div. 2) E - Kefa and Watch

题目大意:给你一个由0-9组成的字符串,有m个询问,两种操作,第一种将l到r的字符全部变成c,第二种问l到r这段 字符串的循环节是不是d. 思路:首先我们要知道怎么判断字符串的循环节的长度是不是d,如果这个字符串小于等于d,那么肯定是的,否则,如果l 到 r-d 和l+d 到 r 这两段字符串则循环节的长度是d,反之不是. 然后我们就用线段树维护区间字符串哈希值就好啦. #include<bits/stdc++.h> #define read(x) scanf("%d",&