Day3下

少女
【問題描述】
你是能看到第一題的 friends呢。
—— hja
少女在圖上開車, 她們但願把每條邊分配給與其相連的點中一個而且每一個點最多被分配一條邊,問可能的方案數。
【輸入格式】
第一行兩個整數 𝑁,𝑀表明點數和邊。
接下來 𝑀行每兩個整數表明一條邊。
【輸出格式】
一行個整數表明答案對 109+7取模以後的值 。
【樣例輸入】
5 4
1 2
3 2
4 5
4 5
【樣例輸出】
6
【數據範圍與規定】
對於 20%的數據, 1≤𝑁≤10。
對於 40%的數據, 1≤𝑁≤100。
對於 100%的數據, 1≤𝑀≤𝑁≤105。ios

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const int P=1e9+7;
int h[N],nex[N*2],to[N*2],cnt;
int n,m;
void add(int x,int y)
{
    to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt;
    to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt;
    return ;
}
bool vis[N],have[N];
queue<int>q;
int dfs(int x)
{
    vis[x]=1;int ans=0,flag=1;
    for(int i=h[x];i;i=nex[i])
    if(!vis[to[i]])
    {        
        flag=0;
        if(!have[x])
        {
            have[x]=1;
            ans+=dfs(to[i]);
            have[x]=0;
        }
        have[to[i]]=1;
        ans+=dfs(to[i]);
        have[to[i]]=0;    
    }
    if(flag)    return 1;
    return ans;
}
int main()
{
    freopen("girl.in","r",stdin);
    freopen("girl.out","w",stdout);    
    scanf("%d%d",&n,&m);
    
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
        
    }
    
    for(int i=1;i<=n;i++)
    if(!vis[i])
    {
        q.push(dfs(i));
    }
    long long ans=1;
    while(!q.empty())
    {
        ans=(ans*q.front())%P;
        q.pop();
    }
    cout<<ans<<'\n';
    return 0;
}
第一遍 但願有分 結果0  
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e5+10;
const int P=1e9+7;
int h[N],nex[N*2],to[N*2],cnt;
int n,m;
void add(int x,int y,int k)
{
    to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt;    
    to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt;
    return ;
}
bool vis[N],cirl;
long long ans=1,size;
void dfs(int x,int last)
{
    size++;    
    vis[x]=1;
    for(int i=h[x];i;i=nex[i])
    if(to[i]!=last)
    {        
        if(vis[to[i]])
        {
            cirl=1;
            continue;
        }else
        dfs(to[i],x);
    }
    return ;
}
int t1,t2;
int main()
{
    freopen("girl.in","r",stdin);
    freopen("girl.out","w",stdout);    
    scanf("%d%d",&n,&m);    
    for(int i=1,x,y;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y,i);        
    }    
    for(int i=1;i<=n;i++)
    if(!vis[i])
    {
        cirl=0;size=0;
        dfs(i,0);
        if(cirl)
            ans=(ans*2LL)%P,t1++;
        else
            ans=(ans*size)%P,t2++;
    }    
    cout<<ans<<'\n';
    return 0;
}
爆搜法AC

注意!默認自環有兩種分配方案。因此我dfs(i,i)是錯的!!!less

 

並查集,維護聯通塊。ide

有環*2,無環(樹)*sum。優化

~~~應該多找幾個樣例試試。 還差一點。 ui

或者dfs序找環。spa

 

終末
【問題描述】
你是能看到第二題的 friends呢。
—— laekov
沒有盡頭的世界之中,咱們想知道 0−𝑁中有多少個數在 𝐾進制下和 −𝐾進制 下的表示方式同樣 。(舉個例子, 4的−3進製表示爲 4=121−3=1×(−3)2+2×(−3)1+1×(−3)0)
【輸入格式】
一行兩個整數 𝑁,𝐾。
【輸出格式】
一行個整數表明答案 。
【樣例輸入】
21 3
【樣例輸出】
9
【數據範圍與規定】
對於 40%的數據 ,𝑁≤1000。
對於另外 30%的數據, 𝐾=2
對於 100%的數據, 1≤𝑁≤1015,2≤𝐾≤103。3d

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
long long n,k;
long long  ans;
int sum;
inline void dfs(long long tot,long long  bas)
{
    if(tot>n)    return;
    ans++;
    for(int i=1;i<k;i++)    
        dfs(tot+i*bas,bas*k*k);
    return ;
}
int main()
{
    freopen("endless.in","r",stdin);
    freopen("endless.out","w",stdout);
    scanf("%lld%lld",&n,&k);
    k=abs(k);
    if(n<=1000)
    {    
        for(int i=0;i<k;i++)        
            dfs(i,k*k);
        cout<<ans<<'\n';
        return 0;
    }    
    sum=log2(n)/log2(k)+1;
    if(sum%2)
    {        
        ans=1;
        for(int i=3;i<=sum;i+=2)
            ans*=k;
        long long tot=0,bas=1;
        for(int i=0;i<=sum;i+=2)        
        {
            tot+=bas*(k-1);
            bas=bas*k*k;
        }
        if(tot<=n)
        {
            cout<<ans*k<<'\n';
            return 0;
        }
        bas/=k*k;
        tot=bas;
        for(int i=0;i<k;i++,tot+=bas)        
            dfs(tot+i,k*k);
        cout<<ans<<'\n';
        return 0;
    }else
    {
        sum=sum/2;
        ans=1;
        for(int i=1;i<=sum;i++)
            ans*=k;
        cout<<ans<<'\n';
    }    
    return 0;
}
但願有分60

 想到了作法,但實現不對。code

奇數位爲0,偶數爲各類數。blog

dp ,!!ci

數位
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
typedef long long LL;
LL n,k;
LL ans;
int sum;
int a[100];
int main()
{
    scanf("%lld%lld",&n,&k);
    int len=0;
    while(n)    a[++len]=n%k,n/=k;
    
    if(len&1)
    {
        for(int i=len;i>=1;i--)
        if(a[i])
        {
            if(!(i&1))
            {
                ans+=pow(k,i/2);
                break;
            }
            ans+=1LL*a[i]*pow(k,i/2);
            if(i==1) ans++;
        }
        cout<<ans;
    }else
        cout<<pow(k,len/2);
        
    return 0;
}
dp

 

 

旅行
【問題描述】
你是能看到第三題的 friends呢。
—— aoao
最後的旅行在樹上,給你一棵 最後的旅行在樹上,給你一棵 𝑁個點的樹,每有權。次你能夠選擇 個點的樹,每有權。次你能夠選擇 個點的樹,每有權。次你能夠選擇 一個點開始旅行,得到這到 一個點開始旅行,得到這到 一個點開始旅行,得到這到 1號點 路徑上全部的權,而後把這些號點 路徑上全部的權,而後把這些號點 路徑上全部的權,而後把這些號點 路徑上全部的權,而後把這些權所有變成 0。你能夠旅行 𝐾次,問能得到的最大點權和。

【輸入格式】
第一行 兩個整數 𝑁,𝐾。
接下來一行 𝑁個整數表明點權。
接下來 𝑁−1行每兩個數表明樹上一條邊。
【輸出格式】
輸出一行表明答案 。
【樣例輸入】
5 2
4 3 2 1
1 2
1 5
2 3
2 4
【樣例輸出】
10
【數據規模與約定】
對於 30%的數據, 1≤𝑁≤10
對於 60%的數據, 1≤𝑁≤100。
對於 100%的數據, 1≤𝑁≤105,0≤𝐾≤𝑁,點權是不超過 ,點權是不超過 231−1

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
using namespace std;
const int N=1e2+10;
int h[N],nex[N*2],to[N*2],cnt;
int n,k;
int f[N],sum[N];
int d[N];
int low[N],tot;
void add(int x,int y)
{
    to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt;
    to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt;
    return ;
}
void build(int x,int fa)
{
    f[x]=fa;
    sum[x]+=sum[fa];
    bool flag=1;
    for(int i=h[x],v;i;i=nex[i])
    if(to[i]!=fa)
    {
        v=to[i];
        build(v,x);
        flag=0;
    }
    if(flag)    low[++tot]=x;
    return ;
}
void Build(int x)
{    
    sum[x]=d[x]+sum[f[x]];
    for(int i=h[x],v;i;i=nex[i])
    if(to[i]!=f[x])
    {
        v=to[i];
        Build(v);    
    }    
    return ;
}
int maxn=0,maxw;long long ans=0;
int main()
{
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&sum[i]);
        d[i]=sum[i];
    }
    for(int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    build(1,0);    
    while(k--)
    {
        maxn=0;
        for(int i=1;i<=tot;i++)
        if(sum[low[i]]>maxn)
        {
            maxn=sum[low[i]];
            maxw=low[i];
        }
        ans+=maxn;
        sum[maxw]=0;
        while(maxw)    d[maxw]=0,maxw=f[maxw];        
        Build(1);
    }
    cout<<ans<<'\n';
    return 0;
}
但願有分60

 思路:

      我只寫了60分就是見一棵樹,求樹上前綴和,每次都把整棵樹都修改一邊。複雜度上是kn。

      固然,這是能夠優化的,咱們須要更改的只是葉結點,

  樹上前綴和,重算一遍。

  優化,區間修改,線段樹來作。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cstring>
#ifdef WIN32
#define ll "%I64d"
#else
#define ll "%lld"
#endif
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
typedef long long LL;
const int M=100001;
int to[M<<1],nt[M<<1],h[M],a[M],cnt=1,tot;
LL w[M],c[M];
void insert_edge(int u,int v){
    to[cnt]=v;nt[cnt]=h[u];h[u]=cnt++;
    to[cnt]=u;nt[cnt]=h[v];h[v]=cnt++;
}
bool cmp(LL x,LL y){
    return x>y;
}
void dfs(int u,int fa){
    LL MAX=0;int vp;
    for(int i=h[u];i;i=nt[i]){
        int v=to[i];
        if(v!=fa){
            dfs(v,u);
            if(w[v]>MAX)MAX=w[v],vp=v;
        }
    }
    w[u]=MAX+a[u];
    for(int i=h[u];i;i=nt[i]){
        int v=to[i];
        if(v!=fa&&v!=vp)c[++tot]=w[v];
    }
}
int main(){
    freopen("tour.in","r",stdin);
    freopen("tour.out","w",stdout);
    int n,k;
    scanf("%d%d",&n,&k);
    rep(i,1,n)scanf("%d",&a[i]);
    memset(h,sizeof(h),0);
    rep(i,1,n-1){
        int u,v;
        scanf("%d%d",&u,&v);
        insert_edge(u,v);
    }
    tot=0;
    dfs(1,1);
    c[++tot]=w[1];
    sort(c+1,c+tot+1,cmp);
    LL ans=0;
    k=min(k,tot);
    rep(i,1,k)ans+=c[i];
    printf(ll"\n",ans);
}
神代碼啊
相關文章
相關標籤/搜索