1. 程式人生 > >2018牛客國慶集訓派對 day3

2018牛客國慶集訓派對 day3

D:很水的簽到題。

#include<bits/stdc++.h>
using namespace std;
int n,m;
double a[1050];
int b[1050];
bool cmp(int x,int y)
{
    return x>y;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        cin>>n>>m;
        int cnt=0;
        for(int i=0; i<n; i++)
        {
            cin>>a[i]>>b[i];
            if(b[i])
                cnt++;
        }
        sort(a,a+n,cmp);
        double ans=0;
        cnt=min(cnt,m);
        for(int i=0;i<cnt;i++)
        {
            ans+=a[i]/2;
        }
        for(int i=cnt;i<n;i++)
            ans+=a[i];
        printf("%.1f\n",ans);
    }
}

H:題意不是很清楚,但是發現和樹的結構沒有關係,只要考慮如何把樹上的結點分成幾部分就可以了,推完發現是個組合數取模,我們預處理階乘,用乘法逆元即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int mod=1e9+7;
ll fac[maxn];
void init_fac()
{
    fac[0]=fac[1]=1;
    for(int i=2;i<maxn;i++)
       fac[i]=i*fac[i-1]%mod;
}
 
ll quickpow(ll a,ll n)
{
    ll ret=1;
    while(n)
    {
        if(n&1) ret=ret*a%mod;
        a=a*a%mod;
        n>>=1;
    }
    return ret;
}
ll C(ll a,ll b)
{
    return fac[a]*quickpow(fac[b],mod-2)%mod*quickpow(fac[a-b],mod-2)%mod;
}
 
int main()
{
    int t;
    scanf("%d",&t);
    init_fac();
    while(t--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        for(int i=1;i<n;i++)
        {
            int x,y;
            scanf("%d %d",&x,&y);
        }
        ll ans=C(n-1,m-1)*fac[m]%mod;
        printf("%lld\n",ans);
    }
}

A:問馬走日最少幾步,原題,可以考慮把終點放在第一象限角平分線的上方,通過找規律可以得出答案。

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int x, y, ans;
    int t;
    cin>>t;
    while(t--)
    {
        cin>>x>>y;
        x=abs(x);
        y=abs(y);
        if(x>y)swap(x, y);

        if(y==x*2)
        {
            printf("%d\n", (x+y)/3);
            continue;
        }
        if(y<=2*x)
        {
            if(x==1&&y==1)
                ans = 2;
            else if(x==2&&y==2)
                ans = 4;
            else
                ans = (x+y)/3+(x+y)%3;
        }
        else
        {
            ans=x;
            int c=(y-2*x)%4;
            ans+=c;
            ans+=(y-2*x-c)/2;
            if(y==1&&x==0)
                ans=3;
        }
        printf("%d\n",ans);
    }
    return 0;
}

I:判斷是否二分圖

有奇環一定不是二分圖,否則一定是二分圖。

最開始我考慮bfs染色,但是發現無法列印環,於是我記錄了成環的2個結點又用了一次dfs搜路徑,然後爆記憶體了。

所以要列印路徑,直接寫dfs即可,但是記住加一個記號判斷是否形成奇環,有奇環層層遞迴退出程式,否則dfs還會一直搜下去,程式會T。

#include<bits/stdc++.h>
using namespace std;
int const maxn=3e5+5;
vector<int>G[maxn];
int color[maxn];
int pre[maxn];
bool iscircle;
bool dfs(int v,int c)
{
    color[v]=c;
    for(int i=0; i<G[v].size(); i++)
    {
        if(color[v]==color[G[v][i]])
        {
            iscircle=true;
            int cnt=0;
            int tem=v;
            int tmp=G[v][i];
            while(v!=tmp)
            {
                cnt++;
                v=pre[v];

            }
            printf("%d\n",cnt+1);
            while(tem!=tmp)
            {
                printf("%d ",tem);
                tem=pre[tem];
            }
            printf("%d ",tem);
            return false;
        }
        if(color[G[v][i]]==0)
        {
            pre[G[v][i]]=v;
            dfs(G[v][i],-c);
            if(iscircle) return false; //這裡要下個標記不然會T
        }
    }
    return true;

}
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1; i<=m; i++)
    {
        int u,v;
        scanf("%d %d",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    memset(color,0,sizeof(color));
    iscircle=false;
    if(dfs(1,1))
    {
        printf("0\n");
        for(int i=1; i<=n; i++)
        {
            if(color[i]==1)
                printf("1 ");
            else printf("0 ");
        }
    }
}

未完待續......