Day5下

T1ios

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N=1010;
int n,m,k,p;
int to[N],nex[N];
int a[N][N];
int main()
{
    freopen("rotate.in","r",stdin);
    freopen("rotate.out","w",stdout);
    scanf("%d%d%d",&n,&p,&k);
    for(int j=1;j<=n;j++)    to[j]=j;
    for(int i=1;i<=p;i++)
    {
        scanf("%d",&m);a[i][0]=m;
        for(int j=1;j<=m;j++)    scanf("%d",&a[i][j]);
    }
    for(int i=p;i>=1;i--)
    {
        memset(nex,0,sizeof nex);m=a[i][0];
        
        for(int j=2;j<=m;j++)    nex[a[i][j-1]]=a[i][j];
        nex[a[i][m]]=a[i][1];
        
        for(int j=1;j<=n;j++)
        if(nex[to[j]])    to[j]=nex[to[j]];
    }
    for(int j=1;j<=n;j++)
    printf("%d ",to[j]);
    return 0;
}
first 100

置換,沒學過的話模擬就行。考察理解題意了。ide

正着作:置換的性質。(不知道也能作)優化

 

T2ui

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N=1e4+100;
int n,a,b,c,d;
int q[N];
long long ans;
int main()
{
    freopen("range.in","r",stdin);
    freopen("range.out","w",stdout);
    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
    
    for(int i=1;i<=n;i++) scanf("%d",&q[i]);
    
    for(int i=1,j;i<=n;i++)
    {
        int ans1,ans2;
        ans1=ans2=q[i];
        if(ans1<a||ans2>d)    continue;
        j=i;
        for(j;j<=n;j++)
        {
            ans1&=q[j];ans2|=q[j];
            if(ans1<a||ans2>d)    break;
            if(ans1<=b&&ans2>=c)    ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
} 
first 60 
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#include<ctime>
using namespace std;
typedef long long  LL;
const int N=1e5+7;
const LL P=1e9+7;
LL ans;
int s[N],sta[N][21],sto[N][21];
int worka(int l,int r)
{
    int L=r-l+1;
    int t=log2(L);
    return sta[l][t]&sta[r-(1<<t)+1][t];
}
int worko(int l,int r)
{
    int L=r-l+1;
    int t=log2(L);
    return sto[l][t]|sto[r-(1<<t)+1][t];
}
int n,a,b,c,d;
int main()
{
    freopen("range.in","r",stdin);
    freopen("range-me.out","w",stdout);
    scanf("%d%d%d%d%d",&n,&a,&b,&c,&d);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&s[i]);
        sta[i][0]=sto[i][0]=s[i];
    }
    
    //預處理倍增,下一步能O(1)查詢區間值 
    for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++)
    if(i+(1<<j)-1 <=n )
    {
        sta[i][j]=sta[i][j-1]&sta[i+(1<<j)][j-1];
        sto[i][j]=sto[i][j-1]|sto[i+(1<<j)][j-1];
    }
    //查找區間(具備單調性)
    for(int i=1;i<=n;i++)
    {
        int andans,orans;
    //    andans=orans=s[i];
        int j=i;
        while(j<=n)
        {
            int L=j,R=n+1,mid;
            andans=worka(i,j);
            orans=worko(i,j);
            while(R-L>1)
            {
                mid=(L+R)>>1;
                if(worka(i,mid)==andans&&worko(i,mid)==orans)
                    L=mid;
                else R=mid;
            }
            if(andans>=a&&andans<=b&& orans>=c&&orans<=d)
            ans+=L-j+1;
            j=L;
        } 
        
    } 
    cout<<ans%P;
}
二分+st優化 

先固定左端典,向右搜,查找區間個數。spa

怎麼優化,二分 +倍增。code

原本我想’與‘和’或‘是不知足 前綴差等於區間值的性質的blog

其實個人想法太狹隘了,仔細想一想:不管是’與‘仍是’或‘ 都知足兩段區間O(1)合成更大區間的性質。string

好比f[1,6] & f[3,9],  能夠當作f[1,3] & f[3,6]&f[6,9] &f[3,6] 一個數和自己的’‘與’仍是自己無影響。it

而後就能經過二分把n^n變成nlogn,io

T3

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N=1009;
const int P=1e9+7;
int n,k;
int h[N],nex[N*2],to[N*2],cnt;
int w[N],sum[N],tot[N];//子樹節點數,根到這的和 
int x,y;
void add()
{
    scanf("%d%d",&x,&y);
    to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt;
    to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt;
}
int vis[N];int ans;
void dfs(int Tot,int Sum,int last)
{
    if(Tot==k)
    {
        int ss=Sum;
        for(int i=1;i<=n;i++)
        if(vis[i])
        for(int j=h[i];j;j=nex[j])
        if(!vis[to[j]])        Sum++;
        Sum=n-1-Sum;
        ans=(1LL*ans+1LL*(1<<Sum)%P)%P;         
        
    
        Sum=ss;    
    }
    if(Tot>k)    return ;
    for(int i=last;i<=n;i++)
    if(vis[i])
    {
        int is=0;
        for(int j=h[i];j;j=nex[j])
        if(!vis[to[j]])    {
            vis[to[j]]=1;
            dfs(Tot+w[to[j]],Sum+1,i);
            vis[to[j]]=0;
        is=1;        
        }        
    }
}
int main()
{
    freopen("fruit.in","r",stdin);
    freopen("fruit.out","w",stdout);
    scanf("%d%d",&n,&k);
    int is=1;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&w[i]);
        if(!w[i])    is=0;
    }
    for(int i=1;i<n;i++)    add();
        
    vis[1]=1;
    dfs(w[1],0,1);
    if(!is) ans--;
    cout<<ans;
    return 0;
}
0分 
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const LL P= 1e9+7;
const int N=1009;
int n,k;
int a[N];
int h[N],nex[N*2],to[N*2],cnt;
LL f[N][N];
int x,y;
void add()
{
    scanf("%d%d",&x,&y);
    to[++cnt]=y,nex[cnt]=h[x],h[x]=cnt;
    to[++cnt]=x,nex[cnt]=h[y],h[y]=cnt;
}
int dfs(int x,int fa)
{
    int sum=1,tmp;
    for(int i=h[x];i;i=nex[i])
    {
        if(to[i]==fa)    continue;
        for(int j=0;j<=n-a[to[i]];j++)
            f[to[i]][j+a[to[i]]]=f[x][j];
        tmp=dfs(to[i],x);
        for(int j=0;j<=n;j++)
        f[x][j]=(f[x][j]*(1<<(tmp-1))+f[to[i]][j])%P;
        sum+=tmp;
    }
    return sum;
}
int main()
{
    freopen("d.in","r",stdin);
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<n;i++)    add();
    
    f[1][a[1]]=1;
    dfs(1,0);
    printf("%lld",(f[1][k]));
}
樹上dp

 

說到T3我就不得不吐槽一下,我投入了整套題考試總時間中超過一半的時間,結果0分。遺憾啊。

搜索 搜重了,不知道怎麼去重。

正解是個揹包(我沒看出來。。。),f[i][j]表示在i節點及其子樹中拿j個果子的方案數,。

轉移的話先遍歷子節點,再根據已有信息更新其餘字節點,和其父節點。

  dp[x][j] = ((1<<(tmp-1) * dp[x][j] % mod + dp[son][j])% mod

(除了直接相連的邊必須斷掉以外,其餘邊怎樣都行,2^n 種狀態。

相關文章
相關標籤/搜索