训练赛Day7 - The 36th ACMICPC Asia Regional Dalian Site —— Onsite Contest
训练赛Day7 - The 36th ACM/ICPC Asia Regional Dalian Site —— Onsite Contest
D - Hexadecimal View
题目大意
十六进制对计算机程序员非常重要和有用。您被要求提供给定数据的十六进制视图。十六进制视图由一行或多行组成。除最后一行之外的每一行代表16个字符。每行由三个以空格分隔的列组成:
- addr:此行的4位十六进制起始地址。
- dump:此行的十六进制表示形式,用空格分隔每两个字符。如果最后一行中少于16个字符,请用空格填充它。
- text:此行的ASCII转换,大写字符转换为小写和小写字符转换为大写。
使用小写字母数字。有关详细信息,请参阅示例。
数据范围
有多个测试用例。每行都是一个测试用例。该行由不少于1个且不超过4096个可打印字符组成,包括空格。
【样例解释】
- 样例输入
Hex Dump
#include <cstdio>
printf("Hello, World!\n");
main = do getLine >>= print . sum . map read . words
- 样例输出
0000: 4865 7820 4475 6d70 hEX dUMP
0000: 2369 6e63 6c75 6465 203c 6373 7464 696f #INCLUDE <CSTDIO
0010: 3e >
0000: 7072 696e 7466 2822 4865 6c6c 6f2c 2057 PRINTF("hELLO, w
0010: 6f72 6c64 215c 6e22 293b ORLD!\N");
0000: 6d61 696e 203d 2064 6f20 6765 744c 696e MAIN = DO GETlIN
0010: 6520 3e3e 3d20 7072 696e 7420 2e20 7375 E >>= PRINT . SU
0020: 6d20 2e20 6d61 7020 7265 6164 202e 2077 M . MAP READ . W
0030: 6f72 6473 ORDS
解题思路
暴力写就行。。。使用%x输出十六进制更方便。
AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
using namespace std;
char s[5000];
string str;
int main() {
while(gets(s)) {
int len = strlen(s);
int tot = 0, res = 0;
str = " ";
for(int i = 0; i < len; i++) {
if(tot == 16) {
cout << str << endl;
str = " ";
tot = 0;
res += 16;
}
if(s[i] >= 'a' && s[i] <= 'z')str += (s[i] + ('A' - 'a'));
else if(s[i] >= 'A' && s[i] <= 'Z')str += (s[i] + ('a' - 'A'));
else str += s[i];
if(tot == 0) {
if(res < 16)printf("000");
else if(res < 16 * 16)printf("00");
else if(res < 16 * 16 * 16)printf("0");
printf("%x:", res);
}
if(tot % 2 == 0)printf(" ");
printf("%x", s[i]);
tot++;
}
if(tot % 2 == 0 && tot != 16)printf(" ");
for(int i = tot + 1; i <= 16; i++) {
printf(" ");
if(i % 2 == 0 && i != 16)printf(" ");
}
if(tot != 0)cout << str << endl;
}
return 0;
}
E - Number String
题目大意
给你一个只包含字符’I’和’D’的字符串,’I’代表当前数字比后面数字值大,’D’代表当前数字比后面数字值小,问你满足该字符串条件的排列的个数。长度为len的串为len+1个数。
数据范围
字符串长度为1到1000,只包含’I’,’D’,’?’,’?’代表该位置可以是’I’也可以是’D’。
解题思路
首先状态为代表前i个数以j结尾满足条件的方案数。
- 即如果第i-1个字符是’I’,即代表第i个数字要比第i-1个数字大,假如第i个数字以j结尾,即。
- 又如果第i-1个字符是’D’,即代表第i个数字要比第i-1个数字小,假如第i个数字以j结尾,即。为什么k可以等于j呢,因为当前i-1个数字最后以j结尾的话,当我第i个数放j时,只要将前面所有大于等于j的数加一,就能保证又满足方案,并且由于前i-1个数最大值是i-1,所以即使加一,在用前i个数时也不会大于i。
- 如果第i-1个字符是’?’,即为两种情况之和,即。
然后前缀和是可以维护的,其实用一维数组就行,我这写时没想太多。。。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const LL Pt = 1e9 + 7;
const int maxn = 1000;
LL dp[maxn + 5][maxn + 5];
LL sum[maxn + 5][maxn + 5];
char s[maxn + 5];
int main() {
while(scanf("%s", s) != EOF) {
int len = strlen(s);
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(dp));
dp[1][1] = 1LL; sum[1][1] = 1LL, sum[1][0] = sum[0][0] = 0LL;
for(int i = 2; i <= len + 1; i++) {
for(int j = 1; j <= i; j++) {
if(s[i - 2] == 'I')dp[i][j] = sum[i - 1][j - 1];
else if(s[i - 2] == 'D')dp[i][j] = ((sum[i - 1][i - 1] - sum[i - 1][j - 1]) % Pt + Pt) % Pt;
else if(s[i - 2] == '?')dp[i][j] = sum[i - 1][i - 1];
sum[i][j] = (sum[i][j - 1] + dp[i][j]) % Pt;
}
}
LL res = 0LL;
for(int i = 1; i <= len + 1; i++)res = (res + dp[len + 1][i]) % Pt;
printf("%lld\n", res);
}
return 0;
}
G - Rescue the Rabbit
题目大意
给你n个串,每个串都有一个价值,并让你构造一个只包含’A’,’C’,’G’,’T’四个字母的长度为l的字符串使得总价值最大。只要在字符串l中出现就算一次答案,并且每个串只记一次。
数据范围
。
解题思路
这种题是想不了的,,,,,AC自动机+DP,首先得预处理出以每个结点结尾的取串状态,这个在处理AC自动机的fail指针和Insert时可以处理。然后代表长度为i的串以trie树上第j个结点结尾状态为k的状态是否存在。然后转移的话,第j个结点可以转移到它的下一个结点,并且取串状态也会更新为新的结点加上当前父节点的状态。最后对于所有存在的状态取最大值,记得要滚动一下。。
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
using namespace std;
const int maxn = 2000;
char s[maxn + 5];
int A[15];
struct AC_Automaton {
struct NOOD {
int next[4];
int fail, end;
}node[maxn + 5];
int size;
bool dp[2][maxn + 5][maxn + 5];
void Init() {
for(int i = 0; i <= maxn; i++) {
memset(node[i].next, -1, sizeof(node[i].next));
node[i].fail = 0, node[i].end = 0;
}
size = 1;
}
int Getx(char c) {
if(c == 'A')return 0;
if(c == 'C')return 1;
if(c == 'G')return 2;
if(c == 'T')return 3;
}
void Insert(char s[], int id) {
int n = strlen(s);
int now = 0;
for(int i = 0; i < n; i++) {
int x = Getx(s[i]);
if(node[now].next[x] == -1)node[now].next[x] = size++;
now = node[now].next[x];
}
node[now].end |= (1 << (id - 1));
}
void Get_fail() {
node[0].fail = -1;
queue<int> que;
for(int i = 0; i < 4; i++) {
if(node[0].next[i] == -1)node[0].next[i] = 0;
else {
node[node[0].next[i]].fail = 0;
que.push(node[0].next[i]);
}
}
while(!que.empty()) {
int u = que.front(); que.pop();
node[u].end |= node[node[u].fail].end;
for(int i = 0; i < 4; i++) {
if(node[u].next[i] == -1)node[u].next[i] = node[node[u].fail].next[i];
else {
node[node[u].next[i]].fail = node[node[u].fail].next[i];
que.push(node[u].next[i]);
}
}
}
}
int Get(int x, int n) {
int res = 0;
for(int i = 1; i <= n; i++)
if((1 << (i - 1)) & x)res += A[i];
return res;
}
void solve(int n, int l) {
memset(dp[0], 0, sizeof(dp[0]));
int t = 0; dp[t][0][0] = 1;
for(int i = 1; i <= l; i++) {
memset(dp[t ^ 1], 0, sizeof(dp[t ^ 1]));
for(int j = 0; j < size; j++) {
for(int k = 0; k < (1 << n); k++) {
for(int x = 0; x < 4; x++) {
dp[t ^ 1][node[j].next[x]][k | node[node[j].next[x]].end] |= dp[t][j][k];
}
}
}
t ^= 1;
}
int Max = -1;
for(int i = 0; i < size; i++)
for(int j = 0; j < (1 << n); j++)
if(dp[t][i][j])Max = max(Max, Get(j, n));
if(Max < 0)printf("No Rabbit after 2012!\n");
else printf("%d\n", Max);
}
}AC;
int main() {
int n, l;
while(~scanf("%d%d", &n, &l)) {
AC.Init();
for(int i = 1; i <= n; i++) {
scanf("%s %d", s, &A[i]);
AC.Insert(s, i);
}
AC.Get_fail();
AC.solve(n, l);
}
return 0;
}
I - The Boss on Mars
题目大意
给定一个数n,找出所有与n互质的数的四次方的和。
数据范围
T组数据,。
解题思路
对于一个数n找出与它互质的数不是很好找,但是找与它有公因子的数还是比较好找的,找出这些数然后用总和减掉就行。但是并不是一下全部找出来减完,而是要用到容斥原理,如果将一个数分成质因子组成的话,比如30 = 2 * 3 * 5;然后要找到所有与它不互质的数,就是要每个质因子即质因子的倍数,这里要减掉所有2的倍数的四次方,再减掉3倍数的四次方,再减掉5倍数的四次方,之后因为会减掉重复的数,比如同时是2和3的倍数,同时是2和5的倍数,同时是3和5的倍数,所以要再加上这些倍数的四次方,然后又会多加,因此又需要再次减掉2和3和5的倍数。就比如要求集合,即可求。之后求前n项四次方的和需要用到一个公式:
若r是n的因子,要求r所有倍数的的因子可以求
AC代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const LL Pt = 1e9 + 7;
LL n;
vector<LL>ans;
LL qwe(LL x, LL y) {
LL t = 1LL;
while(y > 0LL) {
if(y & 1)t = t * x % Pt;
y /= 2LL;
x = x * x % Pt;
}
return t;
}
LL Getsum(LL x) {
return ((x * (x + 1) % Pt * (2 * x + 1) % Pt * (3 * x * x % Pt + 3 * x - 1) % Pt) % Pt + Pt) % Pt * qwe(30, Pt - 2) % Pt;
}
int main() {
int T; scanf("%d", &T);
while(T--) {
ans.clear();
scanf("%lld", &n);
LL x = n;
for(LL i = 2LL; i <= sqrt(n); i++) {
if(x % i == 0LL) {
while(x % i == 0)x /= i;
ans.push_back(i);
}
}
if(x > 1LL)ans.push_back(x);
int size = ans.size();
LL res = 0LL;
for(int i = 0; i < (1 << size); i++) {
int tot = 0; LL tmp = 1LL;
for(int j = 0; j < ans.size(); j++) {
if((1 << j) & i) {
tmp = tmp * ans[j] % Pt;
tot++;
}
}
LL p = tmp;
tmp = ((tmp * tmp % Pt) * tmp % Pt) * tmp % Pt;
if(tot & 1)res = ((res - tmp * Getsum(n / p)) % Pt + Pt) % Pt;
else res = (res + tmp * Getsum(n / p) % Pt) % Pt;
}
printf("%lld\n", res);
}
return 0;
}