2024牛客多校2部分题目
A:Floor Tiles
原题链接:Floor Tiles
首先我们需要明确,对与$ NM$的图,边缘的线头一定有$ 2(NM)$个,故曲线的最少为NM。
再考虑曲线最多的情况,显然,曲线最少时内部没有环,而曲线增多便是要在内部增加环的数量。
若要构造单位圆,显然最优为
但是由于已经确定了一个位置,故可能此排放的顺序有偏差(例如左上角的位置需为B)
故若左上角为A,最多有$N+M+ \lfloor ((N-1)(M-1)+1)/2 \rfloor$
若左上角为B,最多有 $ N+M+ \lfloor ((N-1)(M-1)+1)/2 \rfloor $
构造方法为先确定左上角为A或B,再枚举环的个数,如果足够那就全填A或B,这样保证以后不会出现环。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include<bits/stdc++.h> #define ll long long #define ull unsigned long long #define ld long double using namespace std; const int INF=1e9; int t; int n,m,k; int xx; int yy; char c; int maxn(int m,int n,int flag){ if(flag==0){ return ((n-1)*(m-1)+1)/2; } else return (n-1)*(m-1)/2; } void solve(){ cin>>n>>m>>k; cin>>xx>>yy>>c; int flag=0; if(c=='A'){ flag=(xx+yy)%2; } else flag=(xx+yy+1)%2; int maxn1=maxn(n,m,flag); if(k>maxn1+m+n||k<n+m){ cout<<"No"<<endl; return; } cout<<"Yes"<<endl; int index=k-m-n; if(c=='A'){ for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(index>0){ if((xx+yy)%2==(i+j)%2){ cout<<'A'; if(i!=1&&j!=1)index--; } else cout<<'B'; } else cout<<'A'; } cout<<endl; } } if(c=='B'){ for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(index>0){ if((xx+yy+1)%2==(i+j)%2){ cout<<'A'; if(i!=1&&j!=1)index--; } else cout<<'B'; } else cout<<'B'; } cout<<endl; } } } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>t; while(t--){ solve(); } }
|
B:Taking Candies
原题链接:Taking Candies
从最后开始枚举,假设A在倒数第 i 回合有m个硬币,那么B就有x+y-n个硬币。
显然,B应当使A拿到的更少,自己就能拿到更多,因此B的策略可以为尽量使A拿到的少。
$dp[i][j]$为倒数第 i 回合有 j 块钱,所拿到的最多的糖果数。
显然,当$dp[i][j]<dp[i+1][j-m]+val[i]$时A应花费m拿下,但是B此时应阻挠A拿下,即花费更多。
可使用二分查找到A出价的极限find,即当大于出价大于find时,A拿下不如不拿下,这样可以使B花费最多。
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #define ll long long #define ull unsigned long long #define ld long double using namespace std; int n,x,y; int arr[100005]; ll dp[100005][205]; bool cmp(int x,int y){ return x>y; } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>x>>y; for(int i=1;i<=n;i++)cin>>arr[i]; sort(arr+1,arr+1+n,cmp); int s=x+y; for(int i=n;i>=1;i--){ for(int j=0;j<=s;j++){ int l=0,r=min(j,s-j); int find=-1; while(l<=r){ int mid=(r+l)>>1; if(arr[i]+dp[i+1][j-mid]>dp[i+1][min(s,j+mid)])find=mid,l=mid+1; else r=mid-1; } if((arr[i]+dp[i+1][j-find]>dp[i+1][j+find+1])&&(j+find+1<=s))dp[i][j]=dp[i+1][j+find+1]; else dp[i][j]=arr[i]+dp[i+1][j-find]; } } cout<<dp[1][x]; }
|
I:Red Playing Cards
原题链接:Red Playing Cards
$dp[k]$为$[ l[i] , k]$的最大贡献,$f[i]$为$[l[i],r[i]]$的最大贡献。
在前后各设0,即求$f[0]$。
从大到小枚举,事实上我们需要考虑的仅有当小数包围大数的情况,这种情况我们直接将大数单独考虑即可。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| #include<bits/stdc++.h> using namespace std; const int N = 6005; int dp[N],f[N],l[N],r[N],arr[N];
int n; int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n; for(int i=1;i<=2*n;i++){ cin>>arr[i]; if(l[arr[i]]==0)l[arr[i]]=i; else r[arr[i]]=i; } l[0]=0; r[0]=2*n+1; for(int i=n;i>=0;i--){ int ll=l[i],rr=r[i]; dp[ll]=i; for(int k=ll+1;k<=rr;k++){ int j=arr[k]; if(r[j]==k&&l[j]>ll)dp[k]=max(dp[k-1]+i,dp[l[j]-1]+f[j]); else dp[k]=dp[k-1]+i; } f[i]=dp[rr]; } cout<<f[0]; return 0; }
|