noip模擬題 小奇2 by hzwer[DP][路徑壓縮][分類討論][位運算]

這麼頹下去,遲早要完。

這套題只考了2h,感覺還不錯,T2做過類似的所以A了,T1和T3基本上也沒什麼大問題,關鍵就是要深入挖掘問題特質,學會分類討論(很多題都可以剪掉大量的枝,比如T1,小奇1的T3,noip2015 day1 T3,都是需要有這種分類意識的。
T1:
題意:在座標軸上有一些點有收益,問從0開始,每次只能向前跳4(0+4=4)步或7(0+7=7)步,最大收益是。
數據範圍:
對於20%的數據n=1,m<=10^5
對於40%的數據n<=15,m<=10^5
對於60%的數據m<=10^5
對於100%的數據n<=10^5,m<=10^9,1<=ai<=10^4,1<=bi<=m
分析:
感覺這道題是數據分斥(還是什麼,不知道叫什麼)的典型例子,黃學長這兩套題出的還是不錯的。
20%n=1,只用看能不能去就行了。
60%的數據,m比較小,可以f[i]表示i這個位置的最大值,那麼然後去找-4,-7的最大值就可以了。
100%,經過分析發現,>=18的情況是一定可以走到的!那麼就可以18以內用數組存能不能走,18以外都可以走,在走的時候更新18以內的最大值就可以了!
下面是碎碎念可以不看:
關鍵就是發現>=18的那個性質,這個要求我們多手算找規律啊。
按理說發現>=18以後一百分算法應該順理成章不過我居然沒發現,還是沒養成這種意識。
而且考這套題的時候太zz了,因爲我的算法應該是40分,我想了很久後面那20分怎麼拿,結果拿到解題報告纔想起來,枚舉m的話時間複雜度線性……

60分程序:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "mining"
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,ans,f[Maxn];
struct node
{
    int a,b;
}a[Maxn];
bool cmp(node x,node y)
{
    return x.a<y.a;
}
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init()
{
    n=read();m=read();
    each(i,n){
        a[i].b=read();
        a[i].a=read();
    }
    sort(a+1,a+n+1,cmp);
}
int boo[20]={1,0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1};
int check(int cur,int pre)
{
    if(cur-pre>=18)return 1;
    return boo[cur-pre];
}
void work()
{
    for(int i=1;i<=n;i++){
        int j=i-1;int flg=1;
        for(;j>=0;j--)if(check(a[i].a,a[j].a))
        f[i]=max(f[j]+a[i].b,f[i]);
        ans=max(ans,f[i]);
    }
    printf("%d",ans);
}
void debug()
{
    //
}
int main()
{
    freopen("hop.in","r",stdin);
    freopen("hop.out","w",stdout);
    init();
    work();
    //debug();
    return 0;
}

100分:

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC "mining"
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,ans,maxn,f[Maxn];
struct node
{
    int a,b;
}a[Maxn];
bool cmp(node x,node y)
{
    return x.a<y.a;
}
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init()
{
    n=read();m=read();
    each(i,n){
        a[i].b=read();
        a[i].a=read();
    }
    sort(a+1,a+n+1,cmp);
}
int boo[20]={1,0,0,0,1,0,0,1,1,0,0,1,1,0,1,1,1,0,1,1};
int check(int cur,int pre)
{
    if(cur-pre>=18)return 1;
    return boo[cur-pre];
}
void work()
{
    for(int i=1;i<=n;i++){
        int j=i-1;
        for(;j>=max(0,i-17);j--)if(check(a[i].a,a[j].a))f[i]=max(f[j]+a[i].b,f[i]);
        if(i>18)maxn=max(maxn,f[i-18]);
        if(check(a[i].a,0))f[i]=max(f[i],maxn+a[i].b);
        ans=max(ans,f[i]);
    }
    printf("%d",ans);
}
void debug()
{
    //
}
int main()
{
    freopen("hop.in","r",stdin);
    freopen("hop.out","w",stdout);
    init();
    work();
    //debug();
    return 0;
}

T2:
題意:從帶權矩陣左上角走到右下角(只能向下或向右走),求(n+m1)Σn+m1i=1(AiAavg)2 的最小值.
分析:首先呢我們可以證明對於一個序列,若平均值錯誤,V值一定更小(具體怎麼證?考慮一個長度爲2的序列,把它拆開,看一下,這不是均值不等式嗎)。
然後,你看這權值範圍<=30,一看就可以做奇怪的事。根據最小精度枚舉平均值情況就可以了。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define long long ll
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1,i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC ""
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=305;
int t,n,m,lim,limi,ans,a[Maxn][Maxn],f[Maxn][Maxn];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void init()
{
   n=read();m=read();lim=n+m-1;
   for(int i=2;i<=n;i++)f[i][0]=inf;
   for(int j=2;j<=m;j++)f[0][j]=inf;
   for(int i=1;i<=n;i++)
       for(int j=1;j<=m;j++)
           a[i][j]=read()*lim;
   limi=lim*30;ans=2e9;
}
void work()
{
    for(int i=lim;i<=limi;i++){
        for(int j=1;j<=n;j++)
        for(int k=1;k<=m;k++)
            f[j][k]=min(f[j][k-1],f[j-1][k])+(a[j][k]-i)*(a[j][k]-i);
        ans=min(ans,f[n][m]);
    }
    printf("%d\n",ans/lim);
}
void debug()
{
    //
}
int main()
{
    freopen("matrix.in","r",stdin);
    freopen("matrix.out","w",stdout);
    t=read();
    for(int i=1;i<=t;i++){
    init();
    work();
    }
    //debug();
    return 0;
}

T3:
題意:對於一棵樹,對於每個點,求其他點到這個點的距離分別異或一值的和。
分析:
其實吧,多法圖你就會發現,這個東西,其實可以通過統計最後幾位的01來解決。具體的實現就是,用處理0那種情況(也就是兩次dfs記兩個數組)的方法,再同時處理個01就可以了,然而我當初太天真,寫了個暴力。
碎碎念:多fa圖。
暴力:(好像m!=0處理有錯WA了一組,求大神指點。)

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<ctime>
#define inf 2e8
#define modd 1e9+7
#define clr(x) memset(x,0,sizeof(x))
#define maxen(x) memset(x,127,sizeof(x))
#define maxer(x) memset(x,31,sizeof(x))
#define each(i,n) for(int i=1;i<=n;i++)
#define minn(a,b,c) min(a,min(b,c))
#define maxx(a,b,c) max(a,max(b,c))
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define PROC ""
//for(int i=1;i<=n;i++)
//(double) (ll) LL (int)
//(double)clock()/CLOCKS_PER_SEC
using namespace std;
const int Maxn=1e5+5;
int n,m,a,b,ans,roa[Maxn],g[Maxn],son[Maxn];
int f[Maxn],fr[Maxn],tov[2*Maxn],des[2*Maxn],wor[2*Maxn];
int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void addedge(int cur)
{
    a=read();b=read();wor[2*cur]=wor[2*cur-1]=read();
    tov[2*cur-1]=fr[a];fr[a]=2*cur-1;des[2*cur-1]=b;
    tov[2*cur]=fr[b];fr[b]=2*cur;des[2*cur]=a;
}
void dfs(int u,int fath,long long dis)
{
    if(dis)ans+=dis^m;
    for(int i=fr[u];i;i=tov[i])
        if(des[i]!=fath)
        dfs(des[i],u,dis+(long long)wor[i]);
}
void dfs2(int u,int fath)
{
    for(int i=fr[u];i;i=tov[i])
    if(des[i]!=fath){
        dfs2(des[i],u);
        roa[des[i]]=wor[i];son[u]+=1+son[des[i]];
        f[u]+=f[des[i]]+wor[i]*(son[des[i]]+1);
    }
}
void dfs3(int u,int fath)
{
    g[u]=f[fath]-f[u]+g[fath]+roa[u]*(n-son[u]*2-2);
    for(int i=fr[u];i;i=tov[i])
    if(des[i]!=fath)
        dfs3(des[i],u);
}
void init()
{
   n=read();m=read();
   for(int i=1;i<n;i++)addedge(i);
}
void work()
{
    if(m)
    {
        for(int i=1;i<=n;i++){
            ans=0;dfs(i,0,0LL);
            printf("%d\n",ans);
        }
    }
    else{
        dfs2(1,0);
        f[0]=f[1];dfs3(1,0);
        for(int i=1;i<=n;i++)
            printf("%d\n",f[i]+g[i]);
    }
}
void debug()
{
    //
}
int main()
{
    freopen("tree1.in","r",stdin);
    freopen("tree1.out","w",stdout);
    init();
    work();
    //debug();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章