【Educationcal Codeforces Round 21】

这场edu我原本以为能清真一点……

后来发现不仅是七题

还有各种奇奇怪怪的骚操作……

A.

随便枚举

#include<bits/stdc++.h>
using namespace std;
int n;
int main(){
    scanf("%d",&n);int x=1;
    for(;n/(x*10);x*=10);
    printf("%d\n",n/x*x+x-n);
}

B.

xjb按照定义分一下就行了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n,k,m,a[200010];
double ans;
int main(){
    cin>>n>>k;ll i;
    for(i=1;i<=n;i++)cin>>a[i];
    for(i=1;i<=n;i++)ans+=a[i]*min(min(i,n-i+1),min(k,n-k+1));
    ans/=(n-k+1);
    printf("%16.15f",ans);
}

C.

将茶杯排序,然后从后往前贪心地构造就行了。

#include<bits/stdc++.h>
using namespace std;
int a[1010],b[1010],n,w;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}
int main(){
    n=read();w=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++){b[i]=(a[i]+1)>>1;w-=b[i];}
    if(w<0){puts("-1");return 0;}
    while(w){
        int minv=0;
        for(int i=1;i<=n;i++)if((!minv||a[i]>=a[minv])&&a[i]>b[i])minv=i;
        int x=min(a[minv]-b[minv],w);
        b[minv]+=x;w-=x;
    }
    for(int i=1;i<=n;i++)printf("%d ",b[i]);
}

D.

求出前缀和,二分下标。

#include<bits/stdc++.h>
using namespace std;
int a[1010],b[1010],n,w;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}
int main(){
    n=read();w=read();
    for(int i=1;i<=n;i++)a[i]=read();
    for(int i=1;i<=n;i++){b[i]=(a[i]+1)>>1;w-=b[i];}
    if(w<0){puts("-1");return 0;}
    while(w){
        int minv=0;
        for(int i=1;i<=n;i++)if((!minv||a[i]>=a[minv])&&a[i]>b[i])minv=i;
        int x=min(a[minv]-b[minv],w);
        b[minv]+=x;w-=x;
    }
    for(int i=1;i<=n;i++)printf("%d ",b[i]);
}

E.

大数据版01背包……

不知道正解是啥,我sort一下+鬼畜剪枝玄学过去……

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
typedef long long ll;
int w[N],c[N],rk[N];
int n,m;
ll f[N],p[N];
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}
bool cmp(int x,int y){return p[x]<p[y];}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++){
        w[i]=read();c[i]=read();p[i]=c[i]*6LL/w[i];rk[i]=i;
    }
    sort(rk+1,rk+n+1,cmp);int s=0;
    for(int i=n;i;i--){
        int ww=w[rk[i]],cc=c[rk[i]];
        s+=ww;
        for(int j=s;j>=max(ww,s-50);j--)f[j]=max(f[j],f[j-ww]+cc);
    }
    for(int i=1;i<=m;i++)f[i]=max(f[i],f[i-1]);
    cout<<f[m]<<endl;
}

F.

本场最恶心的题……

首先线性筛出素数,这个不用说。

其次有个显然的单调性。那么我们可以对等级二分答案。

这类问题很模型化,任取两个数不能为素数,那么我们考虑怎样才一定取不出素数。

问题其实也就是一个二分匹配问题,左集合全部为奇数(我们暂时先不考虑1的问题),右集合全部为偶数,那么只有从左边取一个数或者从右边取一个数才可能构成素数。

那么这里就构成了一个二分图模型。

我们考虑建图:

①建立源点,连入各个奇数,流为各个奇数其本身的价值。

②建立汇点,将各个偶数连入汇点,流为各个偶数其本身的价值。

③对应遍历各个奇数,如果其右边有偶数和其相加能够构成素数,那么将其连入那个点,流为INF.

那么我们跑出的最大流就是最小割,也就是最小花费,同样可以理解为最小抛掉的点的价值总和。

那么我们此时最优选取方案的价值和就是Sum-maxlfow.这里Sum就是能够选择的数的价值总和。

于是就这么恶心的写完了……

#include<bits/stdc++.h>
#define N 200005
#define inf 1000000007
using namespace std;
int n,m,opt[N],e,s,t,vis[N];int prime[N],cnt=0;
struct Data{int p,c,l;}a[N];
////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline void calcpri(){
    memset(vis,1,sizeof(vis));
    for(int i=2;i<=N;i++){
        if(vis[i]){prime[++cnt]=i;}
        for(int j=1;j<=cnt;j++){
            int t=i*prime[j];if(t>N)break;
            vis[t]=0;
            if(i%prime[j]==0)break;
        }
    }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Maxflow{

struct Edge{int u,v,f,next;}G[N<<1];
int head[4*N],tot=0;
inline void addedge(int u,int v,int f){
    G[tot].u=u;G[tot].v=v;G[tot].f=f;G[tot].next=head[u];head[u]=tot++;
    G[tot].u=v;G[tot].v=u;G[tot].f=0;G[tot].next=head[v];head[v]=tot++;
}
int level[N];
bool bfs(int s,int t){
    memset(level,0,sizeof(level));
    queue<int>q;q.push(s);level[s]=1;
    while(!q.empty()){
        int u=q.front();q.pop();
        if(u==t)return 1;
        for(int i=head[u];~i;i=G[i].next){
            int v=G[i].v,f=G[i].f;
            if(f&&!level[v])level[v]=level[u]+1,q.push(v);
        }
    }
    return 0;
}
int dfs(int u,int maxf,int t){
    int ret=0;if(u==t)return maxf;
    for(int i=head[u];~i;i=G[i].next){
        int v=G[i].v,f=G[i].f;
        if(f&&level[v]==level[u]+1){
            f=dfs(v,min(maxf-ret,f),t);
            ret+=f;G[i].f-=f;G[i^1].f+=f;
        }
    }
    if(!ret)level[u]=inf;
    return ret;
}
inline void init(){memset(head,-1,sizeof(head));tot=0;}
inline int dinic(int s,int t){
    int ans=0;
    while(bfs(s,t))ans+=dfs(s,inf,t);
    return ans;
}

}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
bool check(int x){
    int k=0;for(int i=1;i<=n;i++)if(a[i].l<=x)if(a[i].c==1&&a[i].p>a[k].p)k=i;
    Maxflow::init();
    int s=0,t=n+1;
    int sum=0;
    for(int i=1;i<=n;i++)if(a[i].l<=x){
        if(a[i].c==1&&i!=k)continue;
        sum+=a[i].p;if(a[i].c&1)Maxflow::addedge(s,i,a[i].p);
        else Maxflow::addedge(i,t,a[i].p);
    }
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(vis[a[i].c+a[j].c]){
        if(a[i].c&1)Maxflow::addedge(i,j,inf);
        else Maxflow::addedge(j,i,inf);
    }
    return (sum-Maxflow::dinic(s,t)>=m);
}

inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==‘-‘)f=-1;}while(ch<‘0‘||ch>‘9‘);
    do{x=x*10+ch-‘0‘;ch=getchar();}while(ch>=‘0‘&&ch<=‘9‘);
    return f*x;
}

int main(){
    n=read();m=read();calcpri();
    for(int i=1;i<=n;i++)a[i].p=read(),a[i].c=read(),a[i].l=read();
    int l=1,r=0,ret=0;
    for(int i=1;i<=n;i++)r=max(r,a[i].l);ret--;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid))ret=mid,r=mid-1;
        else l=mid+1;
    }
    printf("%d\n",ret);
}

G.

一个挺妙的dp。

记录dp[i],表示到了位置i最多的出现次数。

cnt[i],表示最后一次出现的 B 以 i 结尾 0-i中最多能出现几次B

首先dp[i]初始为dp[i-1]

接着用kmp,O(m)求出可以从之前的哪个位置转移

求和之后比较即可。

#include<bits/stdc++.h>
#define N 100005
using namespace std;
char s[N],p[N];
int nxt[N],dp[N],cnt[N];
void calcnext(char *s,int len,int *nxt){
    int i=0,j;nxt[0]=j=-1;
    while(i<len){
        while(j!=-1&&s[i]!=s[j])j=nxt[j];
        nxt[++i]=++j;
    }
}
int main(){
    scanf("%s",s);scanf("%s",p);
    calcnext(p,strlen(p),nxt);int slen=strlen(s),plen=strlen(p);
    //for(int i=0;i<plen;i++)printf("%d ",nxt[i]);puts("");
    if(plen>slen){puts("0");return 0;}
    else{
        memset(cnt,0,sizeof(cnt));memset(dp,0,sizeof(dp));
        for(int i=plen-1;i<slen;i++){
            bool sqc=1;
            for(int k=0;k<plen;k++)
            if(s[i-k]!=p[plen-1-k]&&s[i-k]!=‘?‘){sqc=0;break;}
            dp[i]=dp[i-1];
            if(sqc){
                cnt[i]=dp[i-plen];
                for(int k=nxt[plen];~k;k=nxt[k])cnt[i]=max(cnt[i],cnt[i-(plen-k)]);
                cnt[i]++;
                dp[i]=max(dp[i],cnt[i]);
            }
        }
        printf("%d\n",dp[slen-1]);
    }
}

这场没有DS题好差评……

不过有几道好题真是不错的呀。

时间: 2024-08-25 04:13:09

【Educationcal Codeforces Round 21】的相关文章

【Educational Codeforces Round 22】

又打了一场EDU,感觉这场比23难多了啊-- 艹还是我太弱了. A. 随便贪心一下. #include<bits/stdc++.h> using namespace std; int n,sum=0,ans=-1,m; inline int read(){ int f=1,x=0;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9'); do{x=x*10+ch-'0';ch=getchar();}while(

【Educational Codeforces Round 38】D. Buy a Ticket 堆优化Dijkstra

题意 给定一张无向图,对每个点$i\in S$求$\min_{j\in S} {2\times d(i,j)+a_j}$ 考虑多源多汇最短路会超时,换个角度考虑每个$j$,如果$j=i$,那么答案为$a_i$,如果有更优的方案,那么为$i$到$j$的一条路径加上$a_j$,将这个过程看成两条路径,并且将$a_j$独立为一条路径,就得到最短路算法中的松弛操作,可以建立一个超级源点,连向各点,边权为$a_i$,那么从源点跑一遍最短路之后就是每个点所求答案 时间复杂度$O(n\log n)$ 代码 #

【Educational Codeforces Round 37】F. SUM and REPLACE 线段树+线性筛

题意 给定序列$a_n$,每次将$[L,R]$区间内的数$a_i$替换为$d(a_i)$,或者询问区间和 这题和区间开方有相同的操作 对于$a_i \in (1,10^6)$,$10$次$d(a_i)$以内肯定可以最终化为$1$或者$2$,所以线段树记录区间最大值和区间和,$Max\le2$就返回,单点暴力更新,最后线性筛预处理出$d$ 时间复杂度$O(m\log n)$ 代码 #include <bits/stdc++.h> using namespace std; typedef long

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Educational Codeforces Round 21 D. Array Division

题目链接:Educational Codeforces Round 21 D. Array Division 题意: 给你n个数,现在你可以改变1<=个数的位置,然后问你是否存在有一个k,使得sum(a[i])(1<=i<=k)==sum(a[j])(k+1<=j<=n) 题解: 分析: 如果需要将一个数移动,无非就是将这个数从第一部分移到第二部分,或者从第二部分移到第一部分. 所以,我们只需要开两个map来记录一下两部分有哪些数. 当两部分的差值/2等于其中一部分的一个数时

Educational Codeforces Round 21 F. Card Game(网络流之最大点权独立集)

题目链接:Educational Codeforces Round 21 F. Card Game 题意: 有n个卡片,每个卡片有三个值:p,c,l; 现在让你找一个最小的L,使得满足选出来的卡片l<=L,并且所有卡片的p的和不小于k. 选择卡片时有限制,任意两张卡片的c之和不能为质数. 题解: 和hdu 1565 方格取数(2)一样,都是求最大点权独立集. 不难看出来,这题再多一个二分. 注意的是在构造二部图的时候,按照c值的奇偶性构造. 当c==1时要单独处理,因为如果有多个c==1的卡片,

【Codeforces Round 1129】[Alex Lopashev Thanks-Round] (Div. 1)

Codeforces Round 1129 这场模拟比赛做了\(A1\).\(A2\).\(B\).\(C\),\(Div.1\)排名40. \(A\)题是道贪心,可以考虑每一个站点是分开来的,把目的地最小编号的留到最后,所以答案稍微算一下就行了. \(B\)题是道找规律,首先可以很容易地发现只要前面弄个负数的开头,错误算法就会忽略掉这一个值,所以利用这个来构造答案.(最讨厌构造题了)然后推导一番式子就会发现如果我们将第一个值放-1,则 \(\sum_{i=2}^na_i=k+n\), 再更改一

【Codeforces Round 1132】Educational Round 61

Codeforces Round 1132 这场比赛做了\(A\).\(B\).\(C\).\(F\)四题,排名\(89\). \(A\)题\(wa\)了一次,少考虑了一种情况 \(D\)题最后做出来,但被\(hack\)了...被\(hack\)的原因是没有想到答案会超过\(10^{12}\)(毕竟这个时间上的优化也是在最后迫不得已的情况下加的,就没有考虑正确性... Codeforces 1132 C 题意:给一些区间\([l_i,r_i]\),从中删掉两个,求剩下的区间最多能够覆盖的格子数

【Educational Codeforces Round 35 A】 Nearest Minimums

[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 找出最小的数字的位置. 最近的肯定是相邻的某对. [代码] #include <bits/stdc++.h> using namespace std; const int N = 1e5; int n; int a[N+10],mi; int main(){ #ifdef LOCAL_DEFINE freopen("rush_in.txt", "r", stdin); #endif io