1. 程式人生 > >Codeforces Round #510 Div. 2 Virtual Participate記

Codeforces Round #510 Div. 2 Virtual Participate記

  這場打的順手到不敢相信。如果不是vp的話估計肯定打不到這個成績。

  A:最大顯然,最小的話每次暴力給最小的+1。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'
0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 110 int n,m,a[N],mx,s; int main() { /*#ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif*/ n=read(),m=read();
for (int i=1;i<=n;i++) a[i]=read(),s=max(s,a[i]); s+=m; for (int i=1;i<=m;i++) { int mx=1; for (int j=2;j<=n;j++) if (a[j]<a[mx]) mx=j; a[mx]++; } int mx=1;for (int i=1;i<=n;i++) mx=max(mx,a[i]); cout<<mx<<' '<<s;
return 0; }
View Code

  B:每種蔬菜集合取最小值,列舉選哪些即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1010
int n,ans=700000000,f[8];
struct data{int x,y;
}a[N];
int main()
{
/*#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif*/
    n=read();for (int i=1;i<8;i++) f[i]=ans;
    for (int i=1;i<=n;i++)
    {
        a[i].x=read();
        char c=getchar();
        while (c<'A'||c>'Z') c=getchar();
        while (c>='A'&&c<='Z')
        {
            a[i].y+=1<<c-'A';
            c=getchar();
        }
        f[a[i].y]=min(f[a[i].y],a[i].x);
    }
    for (int i=0;i<8;i++)
        for (int j=0;j<8;j++)
            for (int k=0;k<8;k++)
            if ((i|j|k)==7) ans=min(ans,f[i]+f[j]+f[k]);
    if (ans==700000000) cout<<-1;
    else cout<<ans;    
    return 0;
}
View Code

  C:顯然就是取一些數使乘積最大。討論一下各種情況。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 200010
int n,a[N];
int main()
{
/*#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif*/
    n=read();
    int cnt=0;
    for (int i=1;i<=n;i++)
    {
        a[i]=read();
        cnt+=a[i]<0;
    }
    int last=0;
    if (cnt%2==0)
    {
        int cnt=0;
        for (int i=1;i<=n;i++)
        if (a[i]==0)
        {
            cnt++;
            if (last) printf("%d %d %d\n",1,last,i);
            last=i;
        }
        if (last&&cnt<n) printf("%d %d\n",2,last);
        last=0;
        for (int i=1;i<=n;i++)
        if (a[i]!=0)
        {
            if (last) printf("%d %d %d\n",1,last,i);
            last=i;
        }
    }
    else
    {
        int mx=0,cnt=0;
        for (int i=1;i<=n;i++)
        if (a[i]<0&&(!mx||a[i]>a[mx])) mx=i;
        for (int i=1;i<=n;i++)
        if (a[i]==0) cnt++,printf("%d %d %d\n",1,i,mx);
        if (cnt<n-1) printf("%d %d\n",2,mx);
        last=0;
        for (int i=1;i<=n;i++)
        if (a[i]!=0&&i!=mx)
        {
            if (last) printf("%d %d %d\n",1,last,i);
            last=i;
        }
    }
    return 0;
}
View Code

  D:字首和後即每次詢問有多少個數與x的和小於y。隨便拿個資料結構維護一下,感覺treap比較方便。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 200010
#define ll long long
#define lson tree[k].ch[0]
#define rson tree[k].ch[1]
int n,root,cnt=0;
ll m,a[N],ans;
struct data{ll x;int p,ch[2],s;
}tree[N];
void up(int k){tree[k].s=tree[lson].s+tree[rson].s+1;}
void move(int &k,int p)
{
    int t=tree[k].ch[p];
    tree[k].ch[p]=tree[t].ch[!p],tree[t].ch[!p]=k,up(k),up(t),k=t;
}
void ins(int &k,ll x)
{
    if (k==0){k=++cnt;tree[k].x=x,tree[k].s=1,tree[k].p=rand();tree[k].ch[0]=tree[k].ch[1]=0;return;}
    tree[k].s++;
    if (x<tree[k].x) {ins(lson,x);if (tree[lson].p>tree[k].p) move(k,0);}
    else {ins(rson,x);if (tree[rson].p>tree[k].p) move(k,1);}
}
ll query(int k,ll s)
{
    if (k==0) return 0;
    if (tree[k].x>s) return query(lson,s);
    else return query(rson,s)+tree[lson].s+1;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    cin>>n>>m;m--;
    srand(20020509);
    for (int i=1;i<=n;i++) a[i]=a[i-1]+read();
    ins(root,0);
    for (int i=1;i<=n;i++)
    {
        ans+=i-query(root,a[i]-m-1);
        ins(root,a[i]);
    }
    cout<<ans;
    return 0;
}
View Code

  E:從小到大倒退期望即可。每次需要知道某格子到其他小於他的格子的距離平方之和,顯然橫縱座標可以分別計算,然後展開即可維護。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1010
#define P 998244353
int n,m,s,sum,Sum[2],Sqr[2],Cnt[2];
int ksm(int a,int k)
{
    int s=1;
    for (;k;k>>=1,a=1ll*a*a%P) if (k&1) s=1ll*s*a%P;
    return s;
}
int trans(int x,int y){return (x-1)*m+y;}
struct data{int x,y,v,ans;
}a[N*N];
bool cmp(const data&a,const data&b)
{
    return a.v<b.v;
}
void update(int k,int x,int p)
{
    a[k].ans=(a[k].ans+1ll*x*x%P*Cnt[p]%P+Sqr[p]-2ll*x*Sum[p]%P+P)%P;
}
void ins(int x,int p)
{
    Cnt[p]++;Sum[p]=(Sum[p]+x)%P;Sqr[p]=(Sqr[p]+1ll*x*x%P)%P;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    n=read(),m=read();
    for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        a[trans(i,j)].x=i,a[trans(i,j)].y=j,a[trans(i,j)].v=read();
    int x=read(),y=read();s=trans(x,y);
    sort(a+1,a+n*m+1,cmp);
    for (int i=1;i<=n*m;i++)
    {
        int t=i;
        while (t<n*m&&a[t+1].v==a[i].v) t++;
        for (int j=i;j<=t;j++)
        {
            a[j].ans=sum;
            update(j,a[j].x,0),update(j,a[j].y,1);
            a[j].ans=1ll*a[j].ans*ksm(i-1,P-2)%P;
        }
        for (int j=i;j<=t;j++)
        {
            ins(a[j].x,0),ins(a[j].y,1);
            sum=(sum+a[j].ans)%P;
        }
        i=t;
    }
    for (int i=1;i<=n*m;i++)
    if (trans(a[i].x,a[i].y)==s) {cout<<a[i].ans;return 0;}
}
View Code

  F:想了半天覺得一點也不可做,於是大力貪心,莫名其妙就過了。設f[i]為i子樹內劃分集合的最少數量,g[i]為i子樹中這些集合的最大深度的最小值。dp時貪心地合併各子樹內最大深度最小的那些集合,即把小的合併在一塊,大的不管了。並沒有想清楚為什麼對。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 1000010
int n,m,p[N],degree[N],deep[N],fa[N],f[N],g[N],b[N],root,t=0;
struct data{int to,nxt;
}edge[N<<1];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void dp(int k)
{
    bool flag=1;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k]) flag=0,dp(edge[i].to);
    if (flag) f[k]=1,g[k]=0;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k]) f[k]+=f[edge[i].to];
    int cnt=0;
    for (int i=p[k];i;i=edge[i].nxt) 
    if (edge[i].to!=fa[k]) b[++cnt]=g[edge[i].to]+1;
    sort(b+1,b+cnt+1);
    if (cnt) g[k]=b[1];
    for (int i=1;i<cnt;i++)
    if (b[i]+b[i+1]<=m) f[k]--,g[k]=b[i+1];
}
void dfs(int k)
{
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k])
    {
        fa[edge[i].to]=k;
        deep[edge[i].to]=deep[k]+1;
        dfs(edge[i].to);
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("a.in","r",stdin);
    freopen("a.out","w",stdout);
#endif
    n=read(),m=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
        degree[x]++,degree[y]++;
    }
    for (int i=1;i<=n;i++) if (degree[i]>1) {root=i;break;}
    dfs(root);
    dp(root);
    cout<<f[root];
    return 0;
}
View Code

  result:rank 5