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 }
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 }
浙公网安备 33010602011771号