code craft 20
题意: 一共n个人,要选p人作为队员安排在每个位置(每个人在不同位置所产生的贡献不同),另选k人作为观众。问怎么安排使得最后的总贡献最大。每个人作为观众本身的贡献为ai,作为队员在不同位置的贡献为pi
题解: 观察到p的范围很小,所以考虑状压DP。首先我们按照每个人作为观众的贡献从大到小进行排序。可以得出观众只能在前k+p人中选取。这个很容易想啦;
然后就行
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 | #include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; typedef long long ll; const int inf=0x3f3f3f3f; struct Node{ int a,p[7]; bool operator <( const Node &b) const { return a>b.a; } }s[maxn]; ll dp[maxn][200]; int main(){ int n,p,k; cin>>n>>p>>k; for ( int i=1;i<=n;i++){ cin>>s[i].a; } for ( int i=1;i<=n;i++){ for ( int j=0;j<p;j++){ cin>>s[i].p[j]; } } sort(s+1,s+1+n); memset(dp,-inf, sizeof dp); dp[0][0]=0; for ( int i=1;i<=n;i++){ for ( int j=0;j<(1<<p);j++){ ///dp【i】【j】:前i个人时,队员p个位置上j状态的时候最大值 if (i-__builtin_popcount(j)<=k&&i<=k+p) ///首先就是你的i就是第i个人,然后减去你的这i个人里你选的队员个数,这个值说明就是你所选的观众个数,为什么?因为我们是从大到小,前i个既然不是队员的那就是观众,<br> ///观众数量必须小于等于k才说明可以继续放新的观众 dp[i][j]=max(dp[i][j],dp[i-1][j]+s[i].a); ///目前第i个人作为观众 else dp[i][j]=dp[i-1][j]; for ( int t=0;t<=p;t++){ if (j&(1<<t)){ dp[i][j]=max(dp[i][j],dp[i-1][j-(1<<t)]+s[i].p[t]); ///第i个人作为队员 } } } } cout<<dp[n][(1<<p)-1]<< "\n" ; return 0; } |
D
题意:给你n*n的方格,然后每个格子本来有5个操作分别表示如果你此时在这个格子,就得按照字母进行其中一项操作,上,下,左,右,原地不动,但是现在这些字母不见了,但是你知道的是如果你此时在x,y点,再经过方格上的操作后最终目的地,如果是-1,-1的话说明一直走动停不下来
首先我们可以先在输入的时候对于x=i,y=j,先给存入答案x,因为他们的目的地是本身这个格子嘛,接下来就是其他格子如果没有-1-1,那么他们肯定是会沿着一条路径前往到其他一个点例如a,b停止,也就是这条路径上的点都会是a,b这个目的地坐标,所以我们由第一开始的x点dfs出去,若此时在该点的上面得到和x相同坐标的点,那么此时这个新的点操作肯定是‘D’,表示向下,同时vis标记该点有答案了
那-1,-1这种情况呢?那他肯定是由一个个-1,-1组成个死循环,所以我们反过来,由该点上面得到-1,-1这个新点,那么你此时这个点就是‘U'表示向上,然后再dfs这个新的点;
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 73 74 75 76 77 78 79 | #include <bits/stdc++.h> typedef long long ll; using namespace std; typedef pair< int , int > pp; const int N=1e3+5; const int mod=1e9+7; const int inf=0x3f3f3f3f; const double pi=acos(-1); const double eps=1e-6; mt19937 rnd(time(0)); pp g[N][N]; int vis[N][N]; char ans[N][N]; int dx[4]={1,-1,0,0}; int dy[4]={0,0,-1,1}; char d[4]={ 'U' , 'D' , 'R' , 'L' }; char fd[4]={ 'D' , 'U' , 'L' , 'R' }; void dfs( int x, int y) { for ( int i=0;i<4;i++){ int xx=x+dx[i]; int yy=y+dy[i]; if (vis[xx][yy]) continue ; if (g[x][y].first==g[xx][yy].first&&g[x][y].second==g[xx][yy].second) { ans[xx][yy]=d[i]; vis[xx][yy]=1; dfs(xx,yy); } } } int main() { int n; scanf( "%d" ,&n); for ( int i=1;i<=n;i++){ for ( int j=1;j<=n;j++){ int x,y; scanf( "%d%d" ,&x,&y); g[i][j]={x,y}; if (x==i&&y==j)ans[x][y]= 'X' ,vis[x][y]=1; } } for ( int i=1;i<=n;i++){ for ( int j=1;j<=n;j++){ if (g[i][j].first==-1){ for ( int k=0;k<4;k++){ int x=i,y=j; int xx=x+dx[k]; int yy=y+dy[k]; if (g[x][y].first==g[xx][yy].first&&g[x][y].second==g[xx][yy].second) { ans[x][y]=fd[k]; vis[x][y]=1; break ; } } } else { if (ans[i][j]== 'X' )dfs(i,j); } } } for ( int i=1;i<=n;i++){ for ( int j=1;j<=n;j++){ if (!vis[i][j]){ printf( "INVALID\n" ); return 0; } } } printf( "VALID\n" ); for ( int i=1;i<=n;i++){ for ( int j=1;j<=n;j++){ printf( "%c" ,ans[i][j]); }puts( "" ); } return 0; } |
C
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 | #include<bits/stdc++.h> #define rep(i,a,b) for(int i=a;i<=(b);++i) #define mem(a,x) memset(a,x,sizeof(a)) #define pb push_back #define pi pair<int, int> #define mk make_pair using namespace std; typedef long long ll; const int N=1e6+10; const ll mod=1e9+7; ll a[N],b[N],n,m,p,ans1,ans2; ll input(){ ll x=0,f=0; char ch=getchar(); while (ch< '0' ||ch> '9' ) f|=ch== '-' ,ch=getchar(); while (ch>= '0' &&ch<= '9' ) x=x*10+ch- '0' ,ch=getchar(); return f? -x:x; } int main() { n=input(); m=input(); p=input(); rep(i,1,n) a[i]=input(); for ( int i=1;i<=n;i++) if (a[i]%p&&ans1==0) ans1=i; rep(i,1,m) b[i]=input(); for ( int i=1;i<=m;i++) if (b[i]%p&&ans2==0) ans2=i; printf( "%lld\n" ,ans1+ans2-2); } |
B
给定一个长度为nn的字符串ss。现规定一种操作。规则如下:
选定一个kk,(1≤k≤n)(1≤k≤n),依次从11开始到n−k+1n−k+1的下标向后截取长度为kk的字符串并将其翻转。问kk取多少可以使得操作后的字符串字典序最小。
会发现其实就是后面的一部分变成新的字符串的前面一串,原字符串的前面变为新字符串的后面部分,同时后面这部分字符串如果k是奇数他还得翻转一次
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 | #include<bits/stdc++.h> #define maxn 5005 using namespace std; int T,n; char str[maxn]; pair< string , int > s[maxn]; int main() { scanf( "%d" ,&T); while (T--) { memset(str,0, sizeof (str)); scanf( "%d" ,&n); scanf( "%s" ,str+1); for ( int i=1;i<=n;++i) { string tmp; for ( int j=i;j<=n;++j)tmp.push_back(str[j]); if ((n&1)==(i&1)) for ( int j=i-1;j>=1;--j)tmp.push_back(str[j]); else for ( int j=1;j<i;++j)tmp.push_back(str[j]); s[i]=make_pair(tmp,i); } sort(s+1,s+n+1); for ( int i=1;i<=n;++i)str[i]=s[1].first[i-1]; printf( "%s\n" ,str+1); printf( "%d\n" ,s[1].second); } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步