码迷,mamicode.com
首页 > 其他好文 > 详细

Codeforces Round #441 Div. 2题解

时间:2017-10-17 15:00:24      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:span   硬币   algo   dig   lap   main   tarjan   force   oid   

  比赛的时候E调了好久...F没时间写T T

  A:直接走到短的路上来回走就好了

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=500010,inf=1e9;
int n,a,b,c;
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
int main()
{
    read(n);read(a);read(b);read(c);
    if(n==1)return puts("0"),0;
    int mn=min(a,min(b,c));int now=1;
    if(a==mn||b==mn)printf("%d\n",mn*(n-1));
    else printf("%d\n",min(a,b)+mn*(n-2));
}
View Code

  B:将所有数%m,找到最多的相同的数即可

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=500010,inf=1e9;
int n,k,m,ans,ansi,cntt;
int x[maxn],y[maxn];
int v[maxn];
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
int main()
{
    read(n);read(k);read(m);
    for(int i=1;i<=n;i++)read(x[i]),y[i]=x[i]%m;
    for(int i=1;i<=n;i++)
    {
        v[y[i]]++;
        if(v[y[i]]>ans)
        {
            ans=v[y[i]];
            ansi=y[i];
        }
    }
    if(ans>=k)
    {
        puts("Yes");
        for(int i=1;i<=n;i++)
        {
            if(y[i]==ansi)printf("%d ",x[i]),cntt++; 
            if(cntt==k)return 0;
        } 
     } 
     else puts("No");
}
View Code

  C:答案只可能在[n-100,n]之间,枚举一下就好

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=500010,inf=1e9;
int n,cnt;
int ans[maxn];
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
int main()
{
    read(n);
    for(int i=max(1,n-100);i<=n;i++)
    {
        int x=i,sum=i;
        while(x)
        {
            sum+=x%10;
            x/=10;
        }
        if(sum==n)ans[++cnt]=i;
    }
    printf("%d\n",cnt);
    for(int i=1;i<=cnt;i++)printf("%d ",ans[i]);
}
View Code

  D:最后连续的硬币删掉,前面还剩多少个硬币就是答案

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
using namespace std;
const int maxn=500010,inf=1e9;
int n,x;
bool b[maxn];
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
int main()
{
    puts("1");read(n);int N=n;
    for(int i=1;i<=n;i++)
    {
//        printf("%dQAQ\n",N);
        read(x);b[x]=1;
        while(b[N])N--;
        printf("%d ",i-(n-N)+1);
    }
}
View Code

  E:从每种数字可以改或者不改想到2-SAT,如果第i个字符串比第i+1个字符串小,v[i][j]和v[i+1][j]不一样,那么v[i+1][j]改,v[i][j]就必须改,v[i][j]不改,v[i+1][j]就不能改,如果第i个字符串比第i+1个字符串大,那么v[i][j]必须改,v[i+1][j]不能改,如上连边跑一个可行方案即可。

技术分享
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
#include<map>
#define ll long long 
using namespace std;
const int maxn=200010,inf=1e9;
struct poi{int too,pre,x;}e[maxn<<2],e2[maxn<<2];
int last[maxn],last2[maxn],dfn[maxn],low[maxn],col[maxn],lack[maxn],ru[maxn],rs[maxn],st[maxn],op[maxn];
int n,m,x,y,z,tot,tot2,tott,top,color,flag,len,cnt;
int ans[maxn];
vector<int>v[maxn];
void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
void add(int x,int y){e[++tot].too=y;e[tot].x=x;e[tot].pre=last[x];last[x]=tot;}
void add2(int x,int y){e2[++tot2].too=y;e2[tot2].x=x;e2[tot2].pre=last2[x];last2[x]=tot2;}
int next(int x){return x&1?x+1:x-1;}
void tarjan(int x)
{
    dfn[x]=low[x]=++tott;st[++top]=x;lack[x]=top;
    for(int i=last[x];i;i=e[i].pre)
    if(!dfn[e[i].too])tarjan(e[i].too),low[x]=min(low[x],low[e[i].too]);
    else if(!col[e[i].too])low[x]=min(low[x],dfn[e[i].too]);
    if(dfn[x]==low[x])for(color++;top>=lack[x];top--)col[st[top]]=color;
}
void topsort()
{
    top=0;for(int i=1;i<=color;i++)if(!ru[i])st[++top]=i;
    while(top)
    {
        int now=st[top--];
        if(!rs[now])rs[now]=1,rs[op[now]]=2;
        for(int i=last2[now];i;i=e2[i].pre)
        if(!(--ru[e2[i].too]))st[++top]=e2[i].too;
    }
}
int main()
{
    read(n);read(m);
    for(int i=1;i<=n;i++)
    {
        read(len);
        for(int j=1;j<=len;j++)
        read(x),v[i].push_back(x); 
    }
    for(int i=1;i<n;i++)
    {
        int flagg=0;
        for(int j=0;j<min(v[i].size(),v[i+1].size());j++)
        if(v[i][j]!=v[i+1][j])
        {
            if(v[i][j]<v[i+1][j])add(next(v[i+1][j]<<1),next((v[i][j])<<1)),add(v[i][j]<<1,v[i+1][j]<<1);
            else add(v[i][j]<<1,next((v[i][j])<<1)),add(next((v[i+1][j])<<1),v[i+1][j]<<1);
            flagg=1;break; 
        }
        if(!flagg&&v[i].size()>v[i+1].size())return puts("No"),0;
//        else add(next(v[i][min(v[i].size(),v[i+1].size())]<<1),next((v[i+1][min(v[i].size(),v[i+1].size())])<<1));
    }
    for(int i=1;i<=m<<1;i++)if(!dfn[i])tarjan(i);
    for(int i=1;i<=m;i++)
    {
        if(col[i<<1]==col[next(i<<1)]){printf("No\n");flag=1;break;}
        else op[col[i<<1]]=col[next(i<<1)],op[col[next(i<<1)]]=col[i<<1];
    }
    if(flag)return 0;
    for(int i=1;i<=tot;i++)if(col[e[i].x]!=col[e[i].too])add2(col[e[i].too],col[e[i].x]),ru[col[e[i].x]]++;
    topsort();
//    for(int i=1;i<=tot;i++)printf("QAQ%d %d\n",e[i].x,e[i].too);
    //if(rs[col[(i<<1)]]==rs[col[next(i<<1)]])return puts("No"),0;
    for(int i=1;i<=m;i++)if(rs[col[(i<<1)]]!=1)ans[++cnt]=i;
    printf("Yes\n%d\n",cnt);
    for(int i=1;i<=cnt;i++)printf("%d ",ans[i]); 
    return 0;
}
View Code

  F:预处理出每个数每一位是0的那位左边最近的1和右边最近的1,用单调栈找出每个最大值所在的区间,统计答案即可。

  T T一开始只预处理了20位查了好久错,浅谈状压写多了的后果

技术分享
#include<iostream> 
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cmath> 
#include<algorithm> 
#define ll long long
using namespace std;
const int maxn=500010,inf=2e9;
int n,top;
int st[maxn],a[maxn],digit[maxn][32],pre[maxn][32],Pre[maxn],next[maxn][32],Next[maxn],cnt[maxn];
ll ans;
inline void read(int &k)
{
    int f=1;k=0;char c=getchar();
    while(c<0||c>9)c==-&&(f=-1),c=getchar();
    while(c<=9&&c>=0)k=k*10+c-0,c=getchar();
    k*=f;
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        for(int x=a[i];x;x>>=1)digit[i][++cnt[i]]=x&1;
    }
    for(int j=1,last=0;j<=30;j++,last=0)
    for(int i=1;i<=n;i++)
    {
        if(!digit[i][j])pre[i][j]=last;
        if(digit[i][j])last=i;
    }
    for(int i=1;i<=n;i++)
    for(int j=1;j<=30;j++)
    if(!digit[i][j])
    Pre[i]=max(Pre[i],pre[i][j]);
    memset(next,32,sizeof(next));
    for(int j=1,last=n+1;j<=30;j++,last=n+1)
    for(int i=n;i;i--)
    {
        if(!digit[i][j])next[i][j]=last;
        if(digit[i][j])last=i;
    }
    memset(Next,32,sizeof(Next));
    for(int i=1;i<=n;i++)
    for(int j=1;j<=30;j++)
    if(!digit[i][j])
    Next[i]=min(Next[i],next[i][j]);
    a[++n]=inf;
    for(int i=1;i<=n;i++)
    {
        for(;top&&a[i]>=a[st[top]];top--)
        {
            ans+=1ll*((i-1)-st[top]+1)*(st[top]-(st[top-1]+1)+1);
            ans-=1ll*(1ll*st[top]-1ll*max(st[top-1]+1,Pre[st[top]]+1)+1)*(min(i-1,Next[st[top]]-1)-st[top]+1);
        }
        st[++top]=i;
    }
    printf("%lld\n",ans);
}
View Code

Codeforces Round #441 Div. 2题解

标签:span   硬币   algo   dig   lap   main   tarjan   force   oid   

原文地址:http://www.cnblogs.com/Sakits/p/7681051.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!