1. 程式人生 > >Codeforces Round #485 Div. 1 vp記

Codeforces Round #485 Div. 1 vp記

  A:對每種商品多源bfs一下每個點到該商品的最近距離,對每個點sort一下取前s個即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define int long long
#define N 100010
int n,m,k,s,a[N],p[N],d[110
][N],b[110],q[N],t; 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; } 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 bfs(int k) { int head=0,tail=0;memset(d[k],42,sizeof(d[k])); for (int i=1;i<=n;i++) if (a[i]==k) q[++tail]=i,d[k][i]=0; do { int x=q[++head]; for (int i=p[x];i;i=edge[i].nxt) if (d[k][edge[i].to]>d[k][x]) { d[k][edge[i].to]=d[k][x]+1
; q[++tail]=edge[i].to; } }while (head<tail); } signed main() { #ifndef ONLINE_JUDGE freopen("a.in","r",stdin); freopen("a.out","w",stdout); #endif n=read(),m=read(),k=read(),s=read(); for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=m;i++) { int x=read(),y=read(); addedge(x,y),addedge(y,x); } for (int i=1;i<=k;i++) bfs(i); for (int i=1;i<=n;i++) { for (int j=1;j<=k;j++) b[j]=d[j][i]; sort(b+1,b+k+1); int ans=0; for (int j=1;j<=s;j++) ans+=b[j]; printf("%d ",ans); } return 0; }
View Code

  B:看起來非常玄乎事實上只是說兩人交換次數的奇偶性不同。考慮將原排列變成該排列的最小交換次數,也即n-置換的迴圈節,這個東西的奇偶性是與交換次數的奇偶性有關的,因為每次交換會合並或拆開置換的兩個迴圈。或者可以發現逆序對的奇偶性也是與其相關的,因為顯然交換隻會對兩位置之間的區間產生影響,如果之間的數比兩位置上的數都小或都大顯然沒有影響,否則每有一個這樣的數逆序對變化兩個。同時兩位置本身帶來一個逆序對變化,這樣總逆序對變化量肯定是奇數。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000010
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;
}
int n,a[N];
bool flag[N];
ll s;
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("b.in","r",stdin);
    freopen("b.out","w",stdout);
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    int c=n;
    for (int i=1;i<=n;i++)
    if (!flag[i])
    {
        c--;flag[i]=1;
        int x=a[i];while (!flag[x]) flag[x]=1,x=a[x];
    }
    if ((c&1))
    {
        if (n&1) cout<<"Petr";else cout<<"Um_nik";
    }
    else
    {
        if (n&1) cout<<"Um_nik";else cout<<"Petr";
    }
    return 0;
}
View Code

  1.5h之後C還是沒有思路,自閉到結束。

  result:rank 154

  C:剛的過程中最接近正解的想法是對0~2n-1建一些輔助點,對每個點將每一位挖掉與其連邊,然後將輔助節點取反後連邊,但這樣顯然不對。事實上稍加(?)修改就行了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N (1<<22)
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;
}
int n,m,a[N],b[N],ans;
bool flag[N<<1];
void dfs(int k)
{
    flag[k]=1;
    if (k>(1<<m))
    {
        if (!flag[a[k^(1<<m)]]) dfs(a[k^(1<<m)]);
    }
    else
    {
        for (int i=0;i<m;i++)
        if (!(k&(1<<i))&&!flag[k|(1<<i)]) dfs(k|(1<<i));
        if (b[k^(1<<m)-1]&&!flag[b[k^(1<<m)-1]+(1<<m)]) dfs(b[k^(1<<m)-1]+(1<<m));
    }
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
#endif
    m=read(),n=read();
    for (int i=1;i<=n;i++) b[a[i]=read()]=i;
    for (int i=(1<<m)+1;i<=(1<<m)+n;i++)
    if (!flag[i]) dfs(i),ans++;
    cout<<ans;
    return 0;
}
View Code

   D:題意莫名其妙,實際上是設f(x)為x所有分解因子方式中最小的因子和,求f(x) (x>=n)的最小值。一個古老的結論是因子之和固定時儘量取3能使乘積最大,有剩餘時補2,於是只需考慮這樣的數。求對數可以大致求出答案範圍。列舉每一種可能,高精度求出即可。這需要多項式快速冪。於是就被各種問題折騰了一天。有多慘我已經不想回顧了,最後也不知道怎麼過的。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N (1<<19)
#define M 1500010
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;
}
int n,a[M],r[N],len,ans=100000000;
ll f[N],c[N]; 
char s[M];
const double PI=3.14159265358979323846;
struct complex
{
    double x,y;
    complex operator +(const complex&a) const
    {
        return (complex){x+a.x,y+a.y};
    }
    complex operator -(const complex&a) const
    {
        return (complex){x-a.x,y-a.y};
    }
    complex operator *(const complex&a) const
    {
        return (complex){x*a.x-y*a.y,x*a.y+y*a.x};
    }
}g[N],b[N];
void DFT(complex *a,int n,int op)
{
    for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
    for (int i=2;i<=n;i<<=1)
    {
        complex wn=(complex){cos(2*PI/i),op*sin(2*PI/i)};
        for (int j=0;j<n;j+=i)
        {
            complex w=(complex){1,0};
            for (int k=j;k<j+(i>>1);k++,w=w*wn)
            {
                complex x=a[k],y=w*a[k+(i>>1)];
                a[k]=x+y,a[k+(i>>1)]=x-y;
            }
        }
    }
}
int work(int n,int c)
{
    c*=pow(3,n%6);n/=6;
    memset(f,0,sizeof(f));memset(b,0,sizeof(b));memset(g,0,sizeof(g));
    g[0].x=1;b[0].x=729;int t;
    for (t=2;t<=(n<<1);t<<=1)
    {
        for (int i=0;i<t;i++) r[i]=(r[i>>1]>>1)|(i&1)*(t>>1);
        DFT(b,t,1);
        if (n&(t>>1))
        {
            DFT(g,t,1);
            for (int i=0;i<t;i++) g[i]=g[i]*b[i];
            DFT(g,t,-1);
            for (int i=0;i<t;i++) f[i]=g[i].x/t+0.5;
            for (int i=0;i<t;i++) if (f[i]>999) f[i+1]+=f[i]/1000,f[i]%=1000;
            for (int i=0;i<t;i++) g[i].x=f[i],g[i].y=0;
        }
        if (t>n) break;
        for (int i=0;i<t;i++) b[i]=b[i]*b[i];
        DFT(b,t,-1);
        for (int i=0;i<t;i++) f[i]=b[i].x/t+0.5;
        for (int i=0;i<t;i++) if (f[i]>999) f[i+1]+=f[i]/1000,f[i]%=1000;
        for (int i=0;i<t;i++) b[i].x=f[i],b[i].y=0;
    }
    for (int i=0;i<t;i++) f[i]=g[i].x;
    for (int i=0;i<t;i++) f[i]=f[i]*c;
    for (int i=0;i<t;i++) if (f[i]>999) f[i+1]+=f[i]/1000,f[i]%=1000;
    while (f[t]==0) t--;return t+1;
    //c*729^n
}
int mul(ll *f,int c)
{
    int n=N-1;while (f[n]==0) n--;
    for (int i=0;i<=n;i++) f[i]*=c;
    for (int i=0;i<=n;i++) f[i+1]+=f[i]/1000,f[i]%=1000;
    if (f[n+1]) n++;
    return n+1;
}
bool check(ll *f,int len)
{
    int m=(n-1)/3+1;
    if (len>m) return 1;
    if (len<m) return 0;
    for (int i=m-1;~i;i--)
    if (f[i]!=a[i]) return f[i]>a[i];
    return 1;
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("d.in","r",stdin);
    freopen("d.out","w",stdout);
#endif
    scanf("%s",s+1);n=strlen(s+1);
    for (int i=0;i<n;i++) a[i]=s[n-i]-'0';
    if (n==1&&a[0]==1) {cout<<1;return 0;}
    for (int i=0;i<(n-1)/3+1;i++) a[i]=a[i*3]+a[i*3+1]*10+a[i*3+2]*100;
    len=work(max(floor((n-1)/log10(3))-1,0.0),1);
    for (int k=max(floor((n-1)/log10(3))-1,0.0);k<=ceil(n/log10(3))+1;k++)
    {
        memcpy(c,f,sizeof(c));
        if (check(c,len)) {ans=min(ans,k*3);break;}
        if (check(c,mul(c,2))) {ans=min(ans,k*3+2);break;}
        if (check(c,mul(c,2))) {ans=min(ans,k*3+4);}
        len=mul(f,3);
    }
    cout<<ans;
    return 0;
}
View Code

   E:先考慮序列上怎麼做。考慮每種質因子,問題變為求區間每個數和x取min之和。顯然每個數的質因子數量不會很多,所以對每種質因子個數分別建個BIT即可,複雜度即為log2。可以線性篩預處理做到log分解質因數。樹上問題直接樹剖的話是log3,不太能接受,可以通過尤拉序去一個log,即在進入子樹時加,退出子樹時減。我又被,卡常了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define N 100010
#define M 10000000
#define P 1000000007
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;
}
int n,p[N],a[N],prime[M+10],minp[M+10],deep[N],fa[N][20],in[N],out[N],ans[N],tree[30][N<<1],cnt,m,t;
bool flag[M+10],tmp[30];
struct data{int to,nxt;
}edge[N<<1];
struct data2{int x,y,z,lca;
}q[N];
struct data3{int x,cnt;};
vector<data3> point[M+10],Q[M+10];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void add(int p,int k,int x){while (k<=2*n) tree[p][k]+=x,k+=k&-k;}
int query(int p,int k){int s=0;while (k) s+=tree[p][k],k-=k&-k;return s;}
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;
}
void dfs(int k)
{
    in[k]=out[k]=++cnt;
    for (int i=p[k];i;i=edge[i].nxt)
    if (edge[i].to!=fa[k][0])
    {
        fa[edge[i].to][0]=k;
        deep[edge[i].to]=deep[k]+1;
        dfs(edge[i].to);
        out[k]=++cnt;
    }
}
int lca(int x,int y)
{
    if (deep[x]<deep[y]) swap(x,y);
    for (int j=19;~j;j--) if (deep[fa[x][j]]>=deep[y]) x=fa[x][j];
    if (x==y) return x;
    for (int j=19;~j;j--) if (fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j];
    return fa[x][0];
}
int main()
{
#ifndef ONLINE_JUDGE 
    freopen("e.in","r",stdin);
    freopen("e.out","w",stdout);
#endif
    flag[1]=1;cnt=0;
    for (int i=2;i<=M;i++)
    {
        if (!flag[i]) prime[++cnt]=i,minp[i]=i;
        for (int j=1;j<=cnt&&prime[j]*i<=M;j++)
        {
            flag[prime[j]*i]=1;
            minp[prime[j]*i]=prime[j];
            if (i%prime[j]==0) break;
        }
    }
    n=read();
    for (int i=1;i<n;i++)
    {
        int x=read(),y=read();
        addedge(x,y),addedge(y,x);
    }
    cnt=0;dfs(1);
    fa[1][0]=1;
    for (int j=1;j<20;j++)
        for (int i=1;i<=n;i++)
        fa[i][j]=fa[fa[i][j-1]][j-1];
    for (int i=1;i<=n;i++)
    {
        int x=a[i]=read();
        while (x>1)
        {
            int y=minp[x],cnt=0;
            while (minp[x]==y) cnt++,x/=y;
            point[y].push_back((data3){i,cnt});
        }
    }
    m=read();cnt=0;
    for (int i=1;i<=m;i++)
    {
        q[i].x=read(),q[i].y=read(),q[i].z=read();q[i].lca=lca(q[i].x,q[i].y);ans[i]=1;
        int x=q[i].z;
        while (x>1)
        {
            int y=minp[x],cnt=0;
            while (minp[x]==y) cnt++,x/=y;
            Q[y].push_back((data3){i,cnt});
        }
    }
    fa[1][0]=0;
    int u=25;
    for (int i=1;i<=M;i++)
    if (!flag[i])
    {
        while (ksm(i,u)>M) u--;
        for (int j=0;j<point[i].size();j++)
        {
            add(point[i][j].cnt,in[point[i][j].x],1);
            add(point[i][j].cnt,out[point[i][j].x]+1,-1);
            tmp[point[i][j].cnt]=1;
        }
        for (int j=0;j<Q[i].size();j++)
        {
            ll x=0;
            for (int k=1;k<=Q[i][j].cnt;k++)
            if (tmp[k]) x+=k*(query(k,in[q[Q[i][j].x].x])+query(k,in[q[Q[i][j].x].y])+
            1ll*(P-2)*query(k,in[q[Q[i][j].x].lca])%(P-1)+1ll*(P-2)*query(k,in[fa[q[Q[i][j].x].lca][0]])%(P-1));
            for (int k=Q[i][j].cnt+1;k<=u;k++)
            if (tmp[k]) x+=Q[i][j].cnt*(query(k,in[q[Q[i][j].x].x])+query(k,in[q[Q[i][j].x].y])+
            1ll*(P-2)*query(k,in[q[Q[i][j].x].lca])%(P-1)+1ll*(P-2)*query(k,in[fa[q[Q[i][j].x].lca][0]])%(P-1));
            ans[Q[i][j].x]=1ll*ans[Q[i][j].x]*ksm(i,((x%(P-1))+P-1)%(P-1))%P;
        }
        for (int j=0;j<point[i].size();j++)
        {
            add(point[i][j].cnt,in[point[i][j].x],-1);
            add(point[i][j].cnt,out[point[i][j].x]+1,1);
            tmp[point[i][j].cnt]=0;
        }
    }
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
View Code