这个题晃眼一看,其实就可以知道,是一个比较简单的DP问题。我们设dp[i]表示一直到第 个字母为止 时所能得到的最长神奇字符串的长度。那么,如果第 个字母不在我们最终的最长神奇字符串当中,可以 得到dp[i]=dp[i-1],如果第 个字母在最长神奇字符串当中,那么,这个字母肯定会和最近一个和它相同的 字符进行匹配,记这个位置为pre[s[i]],因此,可以得到dp[i]=max(dp[i1],dp[pre[s[i]-1]]+2) 当然,我们再想一下,这个题就真的只能用DP来解决么?通过分析,我们可以知道,因为我们要得到尽 可能长的满足条件的字符串,那么,就需要尽可能多的添加满足条件的一对字符,因此,我们就可以利 用贪心的思想,给每一个找过的字母打上标记,如果我们发现当前字母在前面的标记中已经出现过了, 那么,我们就让答案+2,并清0所有标记,因为只有这样,我们才可以添加数量尽可能多的字母到字符 串当中。
#includeusing namespace std; string s; int mp[30]; int main() { int t; scanf("%d",&t); while(t--){ memset(mp,0,sizeof(mp)); cin>>s; int len=s.length(),m=0; for(int i=0;i 海盗游戏 对于这个题,我们的最优解肯定是让自己尽可能多的取偶数,而让对手去取奇数。很明显,我们选取金 币的方案跟我们除以4得到的余数是几有关。 如果得到的余数是1或者是3,说明当前金币的数量是奇数,那没办法,我们只能从中取出1枚金币。 如果除以4的余数是2,很明显,这时我们如果取了一半,那么剩下的数就会是一个奇数,这时,我们就 取一半。 如果除以4的余数是0,这时,如果我们取了一半,那么,约翰也能取一半。如果这时我们只取1枚金 币,那么,约翰也只能取1枚金币,这样,我们下次取时,就可以保证我们取完一半之后,约翰也只能取 1枚金币(回到了除以4的余数是2的情况),因此,这时,我们也只取1枚金币(金币数等于4时除外)。 这样,我们就可以得到尽可能多的金币了。
#include五子棋盘using namespace std; int main() { int t; scanf("%d", &t); while (t--) { long long a[2] = {}, u = 0, n; scanf("%lld", &n); while (n) { if (n % 2 == 0 && ((n / 2) % 2 || n == 4)) a[u % 2] += n / 2, n /= 2; else n--, a[u % 2]++; u++; } printf("%lldn", a[0]); } } 这个题是一个比较简单的模拟题。因为每一步棋的位置是确定的,那么,当我们添加一枚棋子以后,就 可以去判断,在当前状态之下,有没有人获得了整场比赛的胜利(即出现了连成5个的情况)。因为出现新 的胜利情况,肯定会和我们新下的这枚棋子有关,因此,我们只需要找与我们新下的这枚棋子成米字型 的这样一个区域的内容即可。
#include能量石int n, a[20][20]; bool check(int x, int y, int z) { a[x][y] = z; int i = x + 1, j = y + 1, s = 1; while (i < 16 && j < 16 && s < 5 && a[i][j] == z) ++s, ++i, ++j; if (s == 5) return 1; i = x - 1,j=y-1; while (i && j && s < 5 && a[i][j] == z) ++s, --i, --j; if (s == 5) return 1; i = x + 1,j=y-1,s=1; while (i < 16 && j && s < 5 && a[i][j] == z) ++s, ++i, --j; if (s == 5) return 1; i = x - 1,j=y+1; while (i && j < 16 && s < 5 && a[i][j] == z) ++s, --i, ++j; if (s == 5) return 1; j = y - 1,s=1; while (j && s < 5 && a[x][j] == z) ++s, --j; if (s == 5) return 1; j = y + 1; while (j < 16 && s < 5 && a[x][j] == z) ++s, ++j; if (s == 5) return 1; i = x - 1,s=1; while (i && s < 5 && a[i][y] == z) ++s, --i; if (s == 5) return 1; i = x + 1; while (i < 16 && s < 5 && a[i][y] == z) ++s, ++i; if (s == 5) return 1; return 0; } int main() { memset(a, -1, sizeof(a)); scanf("%d", &n); for (int i = 1; i <= n; i++) { int x, y; scanf("%d %d", &x, &y); if (check(x, y, i & 1)) { printf("%c %d", (i & 1 ? 'A' : 'B'), i); return 0; } } printf("Tie"); return 0; } 对于这个题而言,解决问题的关键在于如果去处理这个能量消耗的问题。对于任意两个能量石x、y而 言,我们吃掉这两个石头能够得到的能量就为max(x.e+y.e-x.s*y.l , x.e+y.e-y.s*x.l),其中e表示初始能 量,l表示每秒损失的能量,s表示吃掉这个物品所消耗的时间。因此,我们就可以根据这一公式对所有 的石头进行排序,越靠前的石头对整个计算能量消失的比重就越大,就越先进行计算。然后,再将总的 时间看成背包的体积,每个物品的价值看成价值,对这个题进行01背包计算,最终就可以得到答案。
#includeusing namespace std; int dp[10005]; struct node{ int s,e,l; }arr[105]; bool cmp(node x,node y){ return x.s * y.l < y.s * x.l; } int main(){ int t,n,q=0; scanf("%d",&t); while(t--){ memset(dp,0,sizeof(dp)); q++; int m=0; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d%d%d",&arr[i].s,&arr[i].e,&arr[i].l); m+=arr[i].s; } sort(arr+1,arr+n+1,cmp); for(int i=1;i<=n;i++){ for(int j=m;j>=arr[i].s;j--){ dp[j]=max(dp[j],dp[j-arr[i].s]+max(0,arr[i].e-arr[i].l*(j-arr[i].s))); } } int ans=0; for(int i=0;i<=m;i++){ ans=max(ans,dp[i]); } printf("Case #%d: %dn",q, ans); } return 0; }



