[MtOI2019]黑蚊子多

送分向水题,直接模拟即可。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N 1505
 4 using namespace std;
 5 int n,m,k,a[N],now,ans,hve[N];
 6 int main()
 7 {
 8     cin>>n>>m>>k;
 9     for(int i=1;i<=k;i++)cin>>a[i],hve[a[i]]=1;
10     while(now<n)
11     {
12         ans++;
13         now+=m;
14         if(hve[now])m++;
15     }
16     cout<<ans<<endl;
17     return 0;
18 } 

[MtOI2019]膜Siyuan

枚举$x,y$,根据$xor$的性质算出z。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 #define N 2005
 6 using namespace std;
 7 int n,m,a[N],b[N],c[N],ans;
 8 int main()
 9 {
10     //freopen("1.in","r",stdin);
11     //freopen("1.out","w",stdout);
12     cin>>n>>m;
13     for(int i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i];
14     for(int x=1;x<=m;x++)
15     {
16         for(int y=1;y<=m;y++)
17         {
18             int z=((abs(a[1]-x)^abs(b[1]-y)^9)),f=0;
19             //a^b=c
20             //abs(a[1]-x)^abs(b[1]-y)^z=9
21             int zz=c[1]-z;
22             if(zz>m||zz<=0)f=1;
23             for(int i=1;i<=n;i++)
24             {
25                 if((abs(a[i]-x)^abs(b[i]-y)^abs(c[i]-zz))!=9)f=1;
26             }
27             if(!f)ans++;
28             int ff=0,_zz=c[1]+z;
29             if(_zz>m||_zz<=0||zz==_zz)ff=1;
30             for(int i=1;i<=n;i++)
31             {
32                 if((abs(a[i]-x)^abs(b[i]-y)^abs(c[i]-_zz))!=9)ff=1;
33             }
34             if(!ff)ans++;
35         }
36     }
37     cout<<ans<<endl;
38     return 0;
39 }

[MtOI2019]时间跳跃

考试时写了50分做法,枚举每一个边选或不选,然后判断是否是凸多边形,判断一些边能否组成凸多边形很简单,看一下是否出最大值外的权值和是否大于最大值即可。

50分代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define int long long
 5 #define N 5005
 6 #define p (long long)(1e9+7)
 7 using namespace std;
 8 int T,n,ans,a[N];
 9 int ksm(int a,int b)
10 {
11     int r=1;
12     while(b)
13     {
14         if(b&1)r*=a,r%=p;
15         a*=a;a%=p;
16         b>>=1;
17     }
18     return r;
19 }
20 void dfs(int t,int sum,int maxn,int tot)
21 {
22     if(t==n+1)
23     {
24         if(maxn<sum-maxn)
25         {
26             ans+=tot;
27             ans%=p;
28         }
29         return;
30     }
31     a[t]=0;
32     dfs(t+1,sum,maxn,tot);
33     a[t]=1;
34     dfs(t+1,sum+t,t,tot+1);
35 }
36 signed main()
37 {
38     cin>>T;
39     while(T--)
40     {
41         cin>>n;ans=0;
42         dfs(1,0,0,0);
43         cout<<(ans*ksm((1<<n),p-2))%p<<endl;
44     }
45 }

满分做法是$DP$。

设$f_i$为选出边长和为$i$的不合法方案数

设$w_i$为选出边长和为$i$的不合法权值和

对于$f$的转移,直接背包即可。

对于$w$的转移: 我们考虑加入一条长度$i$的边加入边集,那么如果是从$w[j-i]$转移到 $w[j]$, 那么就会在$w[j-i]$的所有状态的边集中加入一条长度为$i$的边然后考虑的不同的边集个数是$f[j-i]$那么在每一个边集中加入一条边的权值和, 就等价于在原本的权值和的基础上加上等同于边集的个数。

然后从小到大枚举并且累加答案即可。

100分代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 5005
#define int long long
#define p (long long)(1e9+7)
using namespace std;
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<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
int ksm(int a,int b)
{
    int r=1;
    while(b)
    {
        if(b&1)r*=a,r%=p;
        a*=a;a%=p;
        b>>=1;
    }
    return r;
}
int T,n,f[N],w[N],s[N];
void init(int n)
{
    f[0]=1;
    for(int i=1;i<=n;i++)
    {
        s[i]=s[i-1];
        for(int j=0;j<=i;j++)s[i]=(s[i]+f[j]+w[j])%p;
        for(int j=n;j>=i;j--)f[j]=(f[j]+f[j-i])%p,w[j]=(w[j]+f[j-i]+w[j-i])%p;
    }
}
signed main()
{
    T=read();
    init(N-5);
    while(T--)
    {
        n=read();
        int xx=ksm(ksm(2,n),p-2)%p,xxx=1ll*n*ksm(2,n-1)%p;
        cout<<(xx*(((xxx-s[n])%p)+p)%p)%p<<endl;
    }
}

[MtOI2019]恶魔之树

等我看懂题解......

01-12 21:12