Loading

20210524 考试总结.

T1 [LOJ6178]景区路线规划

考时操作

想都没想..这显然是一道概率啊~~~

心里想的:这道题我决定使用记忆化搜索..

手上码的:算了不管了..不好想..直接爆搜一个水点儿分过去了..

最终水了 55 分..

考后反思

显然这是一道概率与期望..

对于这道期望题,我更愿意称之为一道概率 。

 

目前以我的认知:

对于我们了解到初状态的题目..

我们可以选择顺推求解..

而对于我们已经知道最终结果的题目..

我们可以选择逆推求解..

无论概率与期望..并无本质区别..

(毕竟期望等于 各个值*相应的概率..)

但是你要是不知道状态怎么定义..那就GoDie了..所以人 sha 就要多做题是正确的..

(在此 %%% WTZ 大佬..)

 

再次回到这道题..

我们发现这道题是一道让我们求解期望的题目..

并且我们知道最初的状态即为随机选择各个点..且该概率相等..

所以我们可以选择正推..

 

这里是 dp 的代码..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double 
#define re register ll
inline void read(ll &ss)
{
    ss=0;
    ll cit=0;
    char ch;
    ch=getchar();
    while(ch>'9' or ch<'0')
    {
        if(ch=='-') cit=1;
        ch=getchar();
    }
    while(ch>='0' and ch<='9')
    {
        ss=(ss<<3)+(ss<<1)+(ch^48);
        ch=getchar();
    }
    if(cit) ss=-ss;
}
ll n;
ll m;
ll less;
ll alls;
ll req[200];
ll h1[200];
ll h2[200];
lf ans1,ans2;
ll xi,yi,ti;
lf g[1000][1000];
ll f[1000];
ll ts;
struct Attractions
{
    ll u;
    ll v;
    ll w;
    ll num;
    ll next;
}a[5000];
inline void add(ll u,ll v,ll w)
{
    a[++ts].u=u;
    a[ts].v=v;
    a[ts].w=w;
    a[ts].num=ts;
    a[ts].next=f[u];
    f[u]=ts;
}
inline lf max(ll aa,ll bb)
{    
    return aa>bb?aa:bb;
}
signed main()
{
    read(n);
    read(m);
    read(alls);
    for(re i=1;i<=n;i++)
    {
        read(req[i]);
        read(h1[i]);
        read(h2[i]);
        g[req[i]][i]=1.0/n;
    }
    for(re i=1;i<=m;i++)
    {
        read(xi);
        read(yi);
        read(ti);
        add(xi,yi,ti);
        add(yi,xi,ti);
    }
    ll num;
    for(re i=0;i<=alls;i++)
    {
        for(re j=1;j<=n;j++)
        {
            num=0;
            for(re k=f[j];k;k=a[k].next)
            {
                if(i+a[k].w+req[a[k].v]<=alls) num++;
            }
            for(re k=f[j];k;k=a[k].next)
            {
                if(i+a[k].w+req[a[k].v]<=alls)
                {
                    g[i+a[k].w+req[a[k].v]][a[k].v]+=g[i][j]/(lf)num;
                }            
            }
        }
    }
    for(re i=1;i<=n;i++)
    {
        for(re j=1;j<=alls;j++)
        {
            ans1+=g[j][i]*h1[i];
            ans2+=g[j][i]*h2[i];
        }
    }
    printf("%.5lf %.5lf",ans1,ans2);
    return 0;
}
T1 code

 

 

T2 [中山市选2009]树

考时操作

嗯哼..元素之间彼此会造成影响..显然高斯消元..

那么这道题会不会产生多组解的困扰..?

算了..直接码..!!!

(打完唯一解的代码之后..)

该考虑考虑多组解了..

诶..?

既然会有自由元的产生..那么最后让求最小操作数..

不管了..直接上 dfs 往回带自由元..

(打完 dfs 的代码之后..)

诶..?

为什么会产生多组解和自由元呢..?

不管了..

把 dfs 的代码注释掉吧..

应该没有自由元..

算了不管了..交上赶紧看下一题..

最后..

 

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define ll long long int
  4 #define lf double 
  5 #define re register ll
  6 const lf eps=1e-8;
  7 inline void read(ll &ss)
  8 {
  9     ss=0;
 10     ll cit=0;
 11     char ch;
 12     ch=getchar();
 13     while(ch>'9' or ch<'0')
 14     {
 15         if(ch=='-') cit=1;
 16         ch=getchar();
 17     }
 18     while(ch>='0' and ch<='9')
 19     {
 20         ss=(ss<<3)+(ss<<1)+(ch^48);
 21         ch=getchar();
 22     }
 23     if(cit) ss=-ss;
 24 }
 25 // xor 或者 mod 2 
 26 ll n;
 27 ll a[150][150];
 28 ll one,two;
 29 ll num;
 30 ll x[150];
 31 /*void dfs(ll left)
 32 {
 33     if(left==0)
 34     {
 35         ll temp;
 36         ll ans=0;
 37         memset(x,0,sizeof(x));
 38         for(re i=n;i>=1;i--)
 39         {
 40             temp=a[i][n+1] & 1;
 41             for(re j=n;j>=i+1;j--)
 42             {
 43                 if(a[i][j]) temp = temp xor x[j];
 44             }
 45             x[i]=temp;
 46             if(x[i]) ans++;
 47         }
 48         minn=min(minn,ans);
 49         return ;
 50     }
 51     else
 52     {
 53         a[n-left+1][n-left+1]=1;
 54         a[n-left+1][n+1]=1;
 55         dfs(left-1);
 56         a[n-left+1][n+1]=0;
 57         dfs(left-1);
 58         return ;
 59     }
 60     return ;
 61 }*/
 62 signed main()
 63 {
 64     //数据应该保证有解..
 65     //但是为了输出最小开关次数,所以需要.. 
 66     read(n);
 67     while(n!=0)
 68     {
 69         memset(a,0,sizeof(a));
 70         for(re i=1;i<=n-1;i++)
 71         {
 72             read(one);
 73             read(two);
 74             a[two][one]=1;
 75             a[one][two]=1;    
 76         }
 77         for(re i=1;i<=n;i++)
 78         {
 79             a[i][i]=1;
 80             a[i][n+1]=1;
 81         }
 82         ll s;
 83         for(re i=1;i<=n;i++) //枚举 i 行  
 84         {
 85             s=0;
 86             for(re j=i;j<=n+1;j++) //枚举 j 列 
 87             {
 88                 for(re k=i;k<=n;k++) // 枚举要被交换的一行
 89                 {
 90                     if(a[k][j]!=0)
 91                     {
 92                         if(k!=i)
 93                         {
 94                             for(re h=1;h<=n+1;h++)
 95                             {
 96                                 swap(a[i][h],a[k][h]);
 97                             }
 98                         }
 99                         s=j;
100                         break;
101                     }
102                     else continue;
103                 }
104                 if(s!=0) break;
105             }
106             for(re j=i+1;j<=n;j++) //开始扫荡,即枚举每一个行,使大于 i 行的第 s 列清空 
107             {
108                 if(a[j][s]%2==0)
109                 {
110                     a[j][s]=0;
111                     continue;
112                 }
113                 for(re k=s;k<=n+1;k++)
114                 {
115                     a[j][k]=a[j][k] xor a[i][k];
116                 }
117             }
118         }
119         /*for(re i=n;i>=1;i--)
120         {
121             ll cit=0;
122             for(re j=1;j<=n+1;j++)
123             {
124                 if(a[i][j]!=0)
125                 {
126                     cit=1;
127                     break;
128                 }
129             }
130             if(cit==0) num++;
131         }*/
132         ll temp;
133         ll ans=0;
134         memset(x,0,sizeof(x));
135         for(re i=n;i>=1;i--)
136         {
137             temp=a[i][n+1] & 1;
138             for(re j=n;j>=i+1;j--)
139             {
140                 if(a[i][j]) temp = temp xor x[j];
141             }
142             x[i]=temp;
143             if(x[i]) ans++;
144         }
145     //    dfs(num);
146         printf("%lld\n",ans);
147         read(n);
148     }
149     return 0;
150 }
这里是赛时代码..

 

 

考后反思

这道题可以选择 高斯消元 或 树形动态规划..

个人认为正解应该是 高斯消元 + 深搜 ..

另外还有一道题:Lights G

这是我个人认为更加普遍的高斯消元求解异或方程组..

还应该加上一些随机化操作..

 

这里是 高斯消元+ dfs 的代码..

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define lf double 
#define re register ll
const lf eps=1e-8;
inline void read(ll &ss)
{
    ss=0;
    ll cit=0;
    char ch;
    ch=getchar();
    while(ch>'9' or ch<'0')
    {
        if(ch=='-') cit=1;
        ch=getchar();
    }
    while(ch>='0' and ch<='9')
    {
        ss=(ss<<3)+(ss<<1)+(ch^48);
        ch=getchar();
    }
    if(cit) ss=-ss;
}
// xor 或者 mod 2 
ll n;
ll a[1500][1500];
ll one,two;
ll num;
ll x[1500];
ll f[1500];
ll cit[1500];
ll minn=1e9;
void dfs(ll left)
{
    //cout<<left<<endl;
    if(left==num)
    {
        ll temp;
        ll ans=0;
        //memset(x,0,sizeof(x));
        for(re i=n;i>=1;i--)
        {
            if(cit[i]) continue;
            temp=a[i][n+1] & 1;
            for(re j=i+1;j<=n;j++)
            {
                if(a[i][j]) temp = temp xor x[j];
            }
            x[i]=temp & 1;
        }
        for(re i=1;i<=n;i++)
        {
            if(x[i]!=0) ans++;
        }
        //cout<<ans<<endl;
        minn=min(minn,ans);
//        cout<<"minn:"<<minn<<endl;
        return ;
    }
    else
    {
        left++;
        cit[f[left]]=1;
        x[f[left]]=1;
        dfs(left);
        x[f[left]]=0;
        dfs(left);
        return ;
    }
    return ;
}
signed main()
{
    //数据应该保证有解..
    //但是为了输出最小开关次数,所以需要.. 
    read(n);
    while(n!=0)
    {
        memset(a,0,sizeof(a));
        memset(f,0,sizeof(f));
        memset(cit,0,sizeof(cit));
        minn=1e9;
        num=0;
        for(re i=1;i<=n-1;i++)
        {
            read(one);
            read(two);
            a[two][one]=1;
            a[one][two]=1;    
        }
        for(re i=1;i<=n;i++)
        {
            a[i][i]=1;
            a[i][n+1]=1;
        }
        ll s;
        for(re i=1;i<=n;i++) //枚举 i 行  
        {
            s=0;
            for(re k=i;k<=n;k++) // 枚举要被交换的一行
            {
                if(a[k][i]!=0)
                {
                    s=1;
                    if(k!=i)
                    {
                        for(re h=1;h<=n+1;h++)
                        {
                            swap(a[i][h],a[k][h]);
                        }
                    }
                    break;
                }
                else continue;
            }
            if(s==0) continue;
            for(re j=i+1;j<=n;j++) 
            {
                if(a[j][i]==0) continue;
                for(re k=i;k<=n+1;k++)
                {
                    a[j][k]=a[j][k] xor a[i][k];
                }
            }
        }
        for(re i=1;i<=n;i++)
        {
            if(a[i][i]==0) 
            {
                num++;
                f[num]=i;
                cit[i]=1;
            }
        }
        ll temp;        
        dfs(0);
        printf("%lld\n",minn);
        read(n);
    }
    return 0;
}
T2 code

 

 

 

 

T3 [JXOI2012]奇怪的道路

考时操作

我竟然认为这是一道排列组合..?

看到这道题题面让求方案数的我:

这不显然是排列组合吗..?

k<=8..??? 算了不重要..

结果最后这道题竟然是一个依靠状压dp AC的题目..

压的就是 k ..

最后我由于时间不够只写了一部分的 code,然后剩下的就靠 ' cout<<0<<endl; ' 骗分了..

写完了估计也不对..

 
考后反思

这道题是一道状压 dp..

看到数据在25以内应该想到状压的..

(另外..看到100左右的数据还应该高斯消元..dd..)

只要想出数组分别代表的含义..然后简单刷个表就可以 AC 了..

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
#define re register ll
const ll p=1000000007;
inline void read(ll &ss)
{
    ss=0;
    ll cit=0;
    char ch;
    ch=getchar();
    while(ch>'9' or ch<'0')
    {
        if(ch=='-') cit=1;
        ch=getchar();
    }
    while(ch>='0' and ch<='9')
    {
        ss=(ss<<3)+(ss<<1)+(ch^48);
        ch=getchar();
    }
    if(cit) ss=-ss;
}
ll n;
ll m;
ll limit;
ll f[35][35][1<<9][10];//前 i 个点,连接了 j 条边,与 i 相邻的前 h 个点的状态为 k,前 h 个点
signed main()
{
    read(n);
    read(m);
    read(limit);
    f[1][0][0][0]=1;// 初始化,对于 i 个点,连接 0 条边,显然方案为 1
    for(re i=1;i<=n;i++)
    {
        for(re j=0;j<=m;j++)
        {
            for(re k=0;k<=(1<<(limit+1))-1;k++)
            {
                for(re h=min(i-1,limit);h>0;h--) // 使得'从i开始向前数个点的状态'转移到当今,即更新状态
                {
                    f[i][j][k][h-1]=(f[i][j][k][h]+f[i][j][k][h-1])%p;
                    f[i][j+1][(k xor 1) xor (1<<h)][h]+=f[i][j][k][h];// 与之相连
                    f[i][j+1][(k xor 1) xor (1<<h)][h]%=p;
                }
                if((k & (1<<limit))==0)
                {
                    f[i+1][j][k<<1][min(i,limit)]+=f[i][j][k][0];
                    f[i+1][j][k<<1][min(i,limit)]%=p;
                }
            }
        }
    }
    printf("%lld",f[n][m][0][0]);
    return 0;
}
                    
    
T3 code

 


 

总结与反思

希望自己在以后做题时多留意一些各个类型破题的关键入口吧..

难题无非就是 困难的思路 + 巨型的码量 + 多样的专题类型结合 ..

要巩固好自己de基础代码能力..(比如dfs..递归..等等)

另外..多去思考..难题总要做过去..

posted @ 2021-05-30 13:59  AaMuXiiiiii  阅读(106)  评论(0编辑  收藏  举报