标签:href include 必须 ase 编号 ffffff code names 开始
前言:一直想练练dp,正好衣神弄了个训练赛。。上次看cgold大佬的题解心血来潮所以自己试着写了第一次题解。。可惜本蒟蒻的能力太差有两道题做不太出,只好搬运学习其它大佬的题解了。。
a题
https://vjudge.net/contest/355951#problem/A
这题做题的过程十分痛苦
我又双叒叕看错题意了。。
以为是必须在对角线上
其实是随便n*n的都行。。
大概思路是从一个角开始更新,统计左边和上边相同的长度
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #include <sstream> #define IOS ios_base::sync_with_stdio(0); cin.tie(0); #define Mod 1000000007 #define eps 1e-6 #define ll long long #define INF 0x3f3f3f3f #define MEM(x,y) memset(x,y,sizeof(x)) #define Maxn 100005 #define P pair<int,int> using namespace std; char a[1005][1005]; int dp[1005][1005]; int n; int main() { int n, ans; while (cin>>n , n) { ans = 1; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) { cin >> a[j][i]; } for (int i = 0; i < n; i++) { for (int j = n - 1; j >= 0; j--) { dp[i][j] = 1; if (i == 0 || j == n - 1) continue; int q = dp[i - 1][j + 1]; for (int k = 1; k <= q; k++) { if (a[i - k][j] == a[i][j + k]) dp[i][j]++; else break; } ans = max(ans, dp[i][j]); } } printf("%d\n", ans); } return 0; }
b题
https://vjudge.net/contest/355951#problem/B
这题有点难。。
蒟蒻直接下线。。。
那就学下网上大佬的方法吧
用dp(j, k)表示,取j 个候选人,使其辩控差为k 的所有方案中,辩控和最大的那个方案(该方案称为“方案dp(j, k)”)的辩控和
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
#include <string>
#include <map>
using namespace std;
#define N 220
#define met(a, b) memset(a, b, sizeof(a))
#define INF 0xffffff
const long long Max = 2000000000;
typedef long long LL;
int D[N], P[N];
int dp[30][1000]; ///dp[i][k]代表选 i 个人, 辩控差为 k 的辩控和最大
int pre[30][1000]; ///pre[i][k] 存的是它是上次选的人
int Answer[N]; ///记录选中的这 m 个人的编号
int main()
{
int n, m, iCase=1;
while(scanf("%d%d", &n, &m), n||m)
{
int i, j, k, Min, t1, t2;
met(D, 0);
met(P, 0);
met(dp, -1);
met(pre, 0);
met(Answer, 0);
for(i=1; i<=n; i++)
scanf("%d%d", &D[i], &P[i]);
Min = m*20; ///它的辩控差最大为 m*20
dp[0][Min] = 0; ///起始状态要先置为 0
/// k 的最大取值范围是[-Min, Min], 但是数组不能表示负数, 因此将数组向右平移 Min,得到[0, 2*Min]
for(i=0; i<=m; i++)
{
for(k=0; k<=Min*2; k++)
{
if(dp[i][k]==-1) continue; ///如果存在,接着找 dp[i][k] 的下一个状态
for(j=1; j<=n; j++)
{
if(dp[i+1][k+D[j]-P[j]] < dp[i][k]+D[j]+P[j])
{
t1=i, t2=k;
while(t1>0 && pre[t1][t2]!=j)
{
t2 -= D[pre[t1][t2]] - P[pre[t1][t2]];
t1 --;
}
if(t1==0) ///当 t1 为 0 时,编号为 j 这个人在之前没有被选中过
{
dp[i+1][k+D[j]-P[j]] = dp[i][k] + D[j] + P[j];
pre[i+1][k+D[j]-P[j]] = j;
}
}
}
}
}
int ff = Min;
int num = 0, sum1=0, sum2=0;
///要选辩控差最小的,所求的 num 便是选 m 个人辩控差最小的
while(dp[m][ff-num]==-1 && dp[m][ff+num]==-1) num++;
if(dp[m][ff-num]>dp[m][ff+num]) t2 = ff-num;
else t2 = ff+num;
t1 = m;
for(i=1; i<=m; i++)
{
Answer[i] = pre[t1][t2];
sum1 += D[Answer[i]];
sum2 += P[Answer[i]];
t1--;
t2 -= D[Answer[i]] - P[Answer[i]];
}
printf("Jury #%d\n", iCase++);
printf("Best jury has value %d for prosecution and value %d for defence:\n", sum1, sum2);
sort(Answer+1, Answer+1+m);
for(i=1; i<=m; i++)
printf(" %d", Answer[i]);
printf("\n\n");
}
return 0;
}
标签:href include 必须 ase 编号 ffffff code names 开始
原文地址:https://www.cnblogs.com/cyq123/p/12296640.html