Topcoder SRM 677 div2

SRM 677 div2
通过数:2
250:
问[L,R]区间内有多少个素数且它是回文数的数。
由于数据范围比较小,直接暴力就可以。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

class PalindromePrime {
public:
    int count(int, int);
};
const int MAXN = 1000 + 50;
int prime[MAXN], cnt;
int vis[MAXN];
int a[10];
bool parliment(int u)
{
    int tcnt = 0;
    while(u) a[++tcnt] = u % 10, u /= 10;
    int head = 1, rear = tcnt;
    while(head < rear){
        if(a[head] != a[rear]) return false;
        head++, rear--;
    }
    return true;
}
void init()
{
    for(int i = 1 ; i < MAXN ; i++) vis[i] = 0;
    cnt = 0;
    for(int i = 2 ; i < MAXN ; i++){
        if(vis[i]) continue;
        if(parliment(i))    prime[cnt++] = i;
        for(int now = i ; now < MAXN ; now += i) vis[now] = 1;
    }
}
int PalindromePrime::count(int L, int R) {
    init();
    int t1, t2;
    t1 = t2 = 0;
    while(t1 < cnt && prime[t1] < L) t1++;
    while(t2 < cnt && prime[t2] <= R) t2++;
    return t2 - t1;
}

<%:testing-code%>
//Powered by [KawigiEdit] 2.0!

550:
四个字符串,可以合成一个字符串,这个字符串的连续子串中包含这四个字符串。
问这个合成的字符串最短多长。
先记录下四个字符串前后连接时相同的地方多少个就可以,手残调了一段时间。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

class FourStrings {
public:
    int shortestLength(string, string, string, string);
};
int len[15][15];
string str[15];
void solve_len()
{
    for(int i = 1 ; i < 5 ; i++){
        for(int j = 1 ; j < 5 ; j++){
            if(i == j) continue;
            else{
                len[i][j] = 0;
                for(int t1 = 0 ; t1 < (int)str[i].size() ; t1++){
                    int ok = 1;
                    for(int t2 = t1 ; t2 - t1 < str[j].size() && t2 < str[i].size(); t2++){
                        if(str[i][t2] != str[j][t2 - t1]){
                            ok = 0;
                            break;
                        }
                    }
                    if(ok){
                        len[i][j] = min(str[i].size() - t1 , str[j].size());
                        break;
                    }
                }
            }
        }
    }
//    for(int i = 1 ; i <= 4 ; i++){
//        for(int j = 1 ; j <= 4 ; j++) printf("%d ", len[i][j]);
//        printf("\n");
//    }
//    printf("\n");
}
int vis[5];
int number[5];
int ans;
void dfs(int u)
{
    if(u == 5){
        int temp = 0;
        int pre = number[1];
        for(int i = 2 ; i <= 4 ; i++){
            temp += len[pre][number[i]];
            if(len[pre][number[i]] < str[number[i]].size()) pre = number[i];
        }
//        if(temp == 4){
//            for(int i = 1 ; i <= 4 ; i++) printf("%d ", number[i]);
//        printf("\n");
//        }
        ans = max(ans, temp);
    }
    else{
        for(int i = 1 ; i < 5 ; i++){
            if(vis[i] == 0){
                number[u] = i;
                vis[i] = 1;
                dfs(u + 1);
                vis[i] = 0;
            }
        }
    }
}
int FourStrings::shortestLength(string a, string b, string c, string d) {
    str[1] = a;
    str[2] = b;
    str[3] = c;
    str[4] = d;
    solve_len();
    for(int i = 1 ; i < 5 ; i++) vis[i] = 0;
    ans = 0;
    for(int i = 1 ; i < 5 ; i++){
        if(vis[i] == 0){
            vis[i] = 1;
            number[1] = i;
            dfs(2);
            vis[i] = 0;
        }
    }
    ans = a.size() + b.size() + c.size() + d.size() - ans;
    return ans;
}

<%:testing-code%>
//Powered by [KawigiEdit] 2.0!

900:
好题啊~
给n个点,起点0,终点1。现在给出边,每个边有一个英文字母编号。
每个点可以重复走,问从起点走到终点、最终走过的边连成的字符串是回文串的最短路径长度多少。
想的时候并没有什么思路,感觉数据范围很想状态压缩DP,但是由于每个点可以重复走就没有办法DP了。
实际上这个思路从开始就是错误的,因为把走的过程看成单纯的从一个点走到另外一个点。然而由于后面走的点没有办法计算,所以这样无法求解。
如果把问题转化一下,看成对于已经是回文串的一段来说,分别向左向右扩展两个相同字符的节点,那么这题就解决了。

#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
using namespace std;

class PalindromePath {
public:
    int shortestLength(int, vector <int>, vector <int>, string);
};
const int MAXN = 20 + 3;
int dp[5][MAXN][MAXN];
int edge[MAXN][MAXN];
vector<int>lin[MAXN];
int PalindromePath::shortestLength(int n, vector <int> a, vector <int> b, string c) {
    int flag = 0;
    memset(edge, -1, sizeof(edge));
    for(int i = 0 ; i < n ; i++) edge[i][i] = 1, lin[i].clear();
    memset(dp, -1, sizeof(dp));
    for(int i = 0 ; i < n ; i++) dp[flag][i][i] = 0;
    for(int i = 0 ; i < (int)a.size() ; i++){
        edge[a[i]][b[i]] = edge[b[i]][a[i]] = c[i] - 'a' + 1;
        dp[!flag][a[i]][b[i]] = dp[!flag][b[i]][a[i]] = 1;
        lin[a[i]].push_back(b[i]);
        lin[b[i]].push_back(a[i]);
    }
//    for(int i = 1 ; i <= n ; i++)
//    if(dp[flag][0][1] != -1) return dp[flag][0][1];
    for(int len = 2 ; len <= (n * n) ; len++){
        for(int x = 0 ; x < n ; x++){
            for(int y = 0 ; y < n ; y++){
                if(dp[flag][x][y] == len - 2){
                    for(int i = 0 ; i < (int)lin[x].size() ; i++){
                        for(int j = 0 ; j < (int)lin[y].size() ; j++){
                            int u = lin[x][i];
                            int v = lin[y][j];
                            if(edge[u][x] == edge[v][y]) dp[(flag + 2) % 3][u][v] = len;
                        }
                    }
                }
            }
        }
        if(dp[flag][0][1] != -1) return dp[flag][0][1];
        flag = (flag + 1) % 3;
    }
    int ans = MAXN*MAXN + 1;
    for(int i = 0 ; i < 4 ; i++) if(dp[i][0][1] != -1) ans = min(ans, dp[i][0][1]);
    if(ans == MAXN * MAXN + 1) return -1;
    else return ans;
}

<%:testing-code%>
//Powered by [KawigiEdit] 2.0!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值