1. 程式人生 > >Codeforces Round #441 Div. 2題解

Codeforces Round #441 Div. 2題解

-- 開始 name getch string ast clu 之間 n-n

  比賽的時候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題解