2019第十届山东ACM省赛部分题解

B、Flipping Game

比赛时一直以为是个组合数找规律的题,今天一想应该要用dp,推了一节毛概课,到晚上终于给A了。

dp[i][j]表示当第i轮有j个不同的时的方案数,那么可以得到初始条件dp[0][num]=1(num表示一开始有多少个灯状态不同,因为接下来递推要用乘法所以初始化为1,这里只需知道dp[0][num]是初始条件即可)

那么dp[i][j]可以怎么得到呢?

首先肯定是从第i-1轮得到,这时假设第i-1轮有p个灯的状态不同,第i轮要有j个灯的状态不同,那么怎么从p到j呢?

可以从p中选择x个变换,从n-p(即相同状态的灯)中选择y个变换,当然x,y不能随便选,因为一轮要变换k个,所以首先x+y==m,还有从p个不同的状态到j个不同的状态还要满足p-x+y==j,

这时列一个二元一次方程组,即可得到y=(j+m-p)/2,这时还要满足y是整数。所以x为 m-y。

所以可以得出状态转移方程 dp[i][j]+=(dp[i-1][p]*C(p,x)%mod*C(n-p,y)%mod)%mod.

求组合数要用杨辉三角求,,否则会超时。。。

还要注意所有地方都要注意取模

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=110;
const int mod=998244353;
ll dp[N][N];  //dp[i][j] 第i轮有j个不同时的方案数
char a[N],b[N];
int n,m,k;
ll c[N][N];
void init()
{
    c[1][1]=1;
    c[0][0]=1;
    c[1][0]=1;
    for(int i=2;i<=110;i++){
        c[i][0]=1;
        for(int j=1;j<=i;j++)
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
    }
}
int main()
{
    int t;
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%d%d%d",&n,&k,&m);
        scanf("%s%s",&a,&b);
        int num=0;
        for(int i=0;i<n;i++)
            if(a[i]!=b[i])
            num++;
        met(dp,0);
        dp[0][num]=1;// 初始化
        for(int i=1;i<=k;i++){
            for(int j=0;j<=n;j++){
                for(int p=0;p<=n;p++){   //上一轮有p个不同
                    if(j+m-p<0)
                        break;
                    if((j+m-p)%2)
                        continue;
                    int y=(j+m-p)/2;  //要满足的条件
                    int x=m-y;   //从p中拿x个,n-p中拿y个
                    if(x>p||y>n-p||x<0)
                    continue;
                dp[i][j]+=(dp[i-1][p]*c[p][x]%mod*c[n-p][y]%mod)%mod;
                dp[i][j]%=mod;
                }
            }
        }
        printf("%lld\n",dp[k][0]%mod);
    }
}

这时n三次方的复杂度即可过。

H、Tokens on the Segments

暴力贪心,比赛时没想到这么贪也能过,以为会T......就没有写

应该是没有给特别大的数据,正解应该用到了优先队列优化成nlogn。

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=1e5+10;
int n,ans;
struct node
{
    int l,r;
}a[N];
bool cmp(node x,node y)
{
    if(x.l==y.l)
        return x.r<y.r;
    return x.l<y.l;
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d%d",&a[i].l,&a[i].r);
        sort(a+1,a+1+n,cmp);
        map<int,int>mp;
        mp.clear();
        ans=0;
        for(int i=n;i>=1;i--){
            for(int j=a[i].r;j>=a[i].l;j--){
                if(mp[j]==0){
                    mp[j]=1;
                    ans++;
                    break;
                }
            }
        }
        printf("%d\n",ans);
    }
}

L、Median

思路:

当输入的两个点相等时,全输出0,当有环的时候也输出全是0

拓扑排序判环,在对于每一个点正向搜索小于它的点,反向搜大于它的点,对于这些点只要满足num1[i]<=n/2 &&num2[i]<=n/2, 即可,对于不同连通图中的点不需要考虑

#include<bits/stdc++.h>
#define exp 1e-8
#define mian main
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ll long long
#define pb push_back
#define PI  acos(-1.0)
#define inf 0x3f3f3f3f
#define w(x) while(x--)
#define int_max 2147483647
#define lowbit(x) (x)&(-x)
#define gcd(a,b) __gcd(a,b)
#define pq(x)  priority_queue<x>
#define ull unsigned long long
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define pl(a,n) next_permutation(a,a+n)
#define ios ios::sync_with_stdio(false)
#define met(a,x) memset((a),(x),sizeof((a)))
using namespace std;
const int N=110;
int head[N],rhead[N];
int num1[N],num2[N];
int in1[N];
int n,m,tot1,tot2;
bool vis[N];
struct node
{
    int ne,v;
}e[N*N],re[N*N];
bool tuopu()//еп╩╥
{
    queue<int>q;
    for(int i=1;i<=n;i++)
        if(in1[i]==0)
            q.push(i);
            int cnt=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();
        cnt++;
        for(int i=head[u];i;i=e[i].ne){
                int v=e[i].v;
            in1[v]--;
            if(in1[v]==0)
                q.push(v);
        }
    }
    return cnt==n;
}
void bfs2()
{
    queue<int>que;
    for(int i=1;i<=n;i++){
            met(vis,0);
      que.push(i);
      int ans=0;
      while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int j=head[u];j;j=e[j].ne){
            int x=e[j].v;
             if(vis[x])
               continue;
            ans++;
            que.push(x);
            vis[x]=1;
        }
      }
      num1[i]=ans;
  }
}
void bfs()
{
    queue<int>que;
    for(int i=1;i<=n;i++){
            met(vis,0);
      que.push(i);
      int ans=0;
      while(!que.empty()){
        int u=que.front();
        que.pop();
        for(int j=rhead[u];j;j=re[j].ne){
            int x=re[j].v;
            if(vis[x])
                continue;
            ans++;
            que.push(x);
            vis[x]=1;
        }
      }
      num2[i]=ans;
  }
}
void add1(int x,int y)
{
    e[++tot1].ne=head[x];
    e[tot1].v=y;
    head[x]=tot1;
}
void add2(int x,int y)
{
    re[++tot2].ne=rhead[x];
    re[tot2].v=y;
    rhead[x]=tot2;
}
int main()
{
    int t;
    scanf("%d",&t);
        while(t--){
            int x,y;
        scanf("%d%d",&n,&m);
        tot1=0;
        tot2=0;
        for(int i=0;i<=n;i++){
                num1[i]=0;
                num2[i]=0;
                head[i]=0;
                rhead[i]=0;
                in1[i]=0;
            }
        bool flag=false;
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            if(x==y)
              flag=true;
            add1(x,y);
            add2(y,x);
            in1[y]++;
        }
        if(flag){
            for(int i=1;i<=n;i++)
                printf("0");
                printf("\n");
            continue;
        }
        if(tuopu()){
            bfs2();
            bfs();
            for(int i=1;i<=n;i++){
                if(num1[i]<=n/2&&num2[i]<=n/2)
                    printf("1");
                else printf("0");
            }
            printf("\n");
        }
        else {
            for(int i=1;i<=n;i++)
                printf("0");
                printf("\n");
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章