2023 ICPC Macau Regional Contest

A. (-1,1)-Sumplete  (思维 + 贪心)

https://codeforces.com/gym/104891/problem/A

https://www.cnblogs.com/yangqingli/p/4735607.html(模仿的格式)

题意:

给你一个n*n(n<=4000)的矩阵,每个字符为'+'或者'-', sij='+'表示aij可以填0或1,‘-’表示可以填0或-1。现给出你第i(1<=i<=n)行的和ri以及第j(1<=j<=n)列的和,现需要你给出一个合法填数方案(如果存在)。若不存在则输出No,存在则给出一个合法方案。


 

解法:

这道题是一道经典的思维题。

 我们先考虑将该问题简化:如果所有的sij='+',这道题该怎么处理呢?

我们不难发现对于每一行,我们使用贪心选取最大的cj,然后在第j列填上一个1即可。可以证明如果存在解则该方案一定合法。

 

那么我们如何将问题简化成上述情况呢? 关键是如何将 -1 0两个选项转化为1 0 。

仔细观察我们可以发现,如果对于-1 0各自加1,则能将其转化为0 1。

 

于是我们成功地将问题转化为了上述情况。 


代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int N=4e3+5;
 4 int n,r[N],c[N];
 5 bool op[N][N];//op=1表示修改了
 6 char s[N][N];
 7 struct node{
 8     int id,x;
 9 }a[N];
10 bool cmp(node b,node c){
11     return b.x>c.x;
12 }
13 bool ans[N][N];
14 int main(){
15     scanf("%d",&n);
16     for(int i=0;i<n;i++)scanf("%s",s[i]);
17     int sum=0;
18     for(int i=0;i<n;i++)scanf("%d",&r[i]),sum+=r[i];
19     for(int i=0;i<n;i++)scanf("%d",&c[i]),sum-=c[i];
20     if(sum){
21         puts("No");
22         return 0;
23     }
24     for(int i=0;i<n;i++){
25         for(int j=0;j<n;j++){
26             if(s[i][j]=='-')op[i][j]=1,r[i]++,c[j]++;
27         }
28     }
29     int ok=1;
30     for(int i=0;i<n;i++){
31         for(int j=0;j<n;j++)a[j].id=j,a[j].x=c[j];
32         sort(a,a+n,cmp);
33         for(int j=0;j<r[i];j++){
34             if(a[j].x){
35                 c[a[j].id]--;
36                 ans[i][a[j].id]=1;
37             }
38             else {
39                 ok=0;
40                 puts("No");
41                 return 0;
42             }
43         }
44     }
45     puts("Yes");
46     for(int i=0;i<n;i++){
47         for(int j=0;j<n;j++)printf("%d",ans[i][j]^op[i][j]);
48         puts("");
49     }
50     return 0;
51 }
View Code

 

  


 H题:Random Tree Parking

题意:https://codeforces.com/gym/104891/problem/H

 


输入样例:

input
15
1 2 2 2 2 3 3 2 7 7 3 10 3 13
output: 938578089

 


题解:

这道题其实不怎么难(顶天Cu中下难度),就是一个一般的树形DP f(i,j), j表示往上走的个数。

考试的时候没做出来是因为没看到"tree T should be generated randomly",导致我不敢写。

所以考试时应当用笔把重点限制条件勾画出来(也要多做题明白哪些是重点条件)。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define ll long long
 4 const int N=1e5+5;
 5 const int M=46;//  最大dep>=M概率<=0.001 
 6 const ll mod=998244353;    
 7 int n,dep[N];//dep+1
 8 struct edges{
 9     int v,nxt;
10 }e[N];
11 int head[N],cnt;
12 void addedge(int u,int v){
13     e[++cnt].v=v;e[cnt].nxt=head[u];head[u]=cnt;
14 }
15 ll f[N][M];//i j(还有j-1个点在上面)
16 ll pw(ll x,ll y){
17     if(y==0)return 1;
18     ll t=pw(x,y/2);
19     t=t*t%mod;
20     if(y%2)t=t*x%mod;
21     return t;
22 } 
23 ll invfac[N],fac[N];
24 void init(){
25     fac[0]=1;invfac[0]=1;
26     for(ll i=1;i<N;i++){
27         fac[i]=fac[i-1]*i%mod;
28         invfac[i]=pw(fac[i],mod-2)%mod;
29     }
30 }
31 void input(){
32     scanf("%d",&n);
33     int x;
34     for(int i=2;i<=n;i++){
35         scanf("%d",&x);
36         addedge(x,i);
37     }
38 }
39 ll g[N][M];
40 
41 void dfs(int u,int fa){
42     dep[u]=dep[fa]+1;
43     for(int i=0;i<=dep[u];i++)f[u][i]=invfac[i];
44     for(int i=head[u];i;i=e[i].nxt){
45         int v=e[i].v;
46         if(v==fa)continue;
47         dfs(v,u);
48         for(int j=dep[u];j>=0;j--){
49             for(int k=min(j,dep[v]);k>=0;k--){//设置临时数组避免重复计算 
50                 g[u][j]+=f[u][j-k]*f[v][k+1]%mod;
51                 continue;
52             }
53             f[u][j]=g[u][j]%mod;g[u][j]=0;
54         }
55     }
56 }
57 int main(){
58     init();input();
59     dep[0]=0; 
60     dfs(1,0);
61     cout<<f[1][1]*fac[n]%mod<<endl;
62     return 0;
63 }
View Code

 

posted @ 2024-01-17 13:05  c201904  阅读(25)  评论(0)    收藏  举报