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");
        }
    }
}

 

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