ICPC网络赛沈阳站补题

K. Supreme Number 
期望难度:easy
考虑到答案中任意一位都必须是1或质数,可知答案只可能由1、2、3、5、7构成。由于任意两个不为1的数字构成 的两位数一定可以被11整除,所以答案中除1外的数字只能出现一次;1最多出现2次,因为111可以被3整除;而 2、5、7三者一定不会有两者同时出现。因此满足条件的整数不会超过四位,全部预处理出来即可

可以推出一共一下几个数字

1
2
3
5
7
11
13
17
23
31
37
53
71
73
113
131
137
173
311
317

然后开始查询就好了

Code就不贴了

D. Made In Heaven 
期望难度:easy K短路模板题。由于数据均为随机生成,直接预处理出每个点到终点的最短路后A*搜索即可。 

贴一个蔡队的代码。。(自己太菜了-.-)

code:
 

#include 
using namespace std;
#define clr(a, x) memset(a, x, sizeof(a))
#define mp(x, y) make_pair(x, y)
#define pb(x) push_back(x)
#define X first
#define Y second
#define fastin                    \
    ios_base::sync_with_stdio(0); \
    cin.tie(0);
typedef long long ll;
typedef long double ld;
typedef pair PII;
typedef vector VI;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;

const int maxn = 1 << 10;
vector G[maxn], rG[maxn];
inline void init(int n)
{
    for (int i = 0; i < n; i++)
    {
        G[i].clear();
        rG[i].clear();
    }
}
inline void add_edge(int u, int v, int w)
{
    G[u].pb(mp(v, w));
    rG[v].pb(mp(u, w));
}
int d[maxn];
bool inq[maxn];
void spfa(int s)
{
    clr(d, 0x3f);
    clr(inq, 0);
    d[s] = 0;
    queue q;
    q.push(s);
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (int i = 0; i < rG[u].size(); i++)
        {
            PII& e = rG[u][i];
            int v = e.X, w = e.Y;
            if (d[v] > d[u] + w)
            {
                d[v] = d[u] + w;
                inq[v] = 1;
                q.push(v);
            }
        }
    }
}
struct HeapNode
{
    int v;
    ll g, f;
    HeapNode(int v, ll g, ll f) : v(v), g(g), f(f) {}
    bool operator<(const HeapNode& rhs) const
    {
        return rhs.f < f || (rhs.f == f && rhs.g < g);
    }
};
bool A_star(int s, int t, int k, int tt)
{
    if (s == t) k++;
    if (d[s] == INF) return false;
    priority_queue q;
    int cnt = 0;
    q.push(HeapNode(s, 0, d[s]));
    while (!q.empty())
    {
        HeapNode tmp = q.top();
        q.pop();
        int u = tmp.v;
        ll g = tmp.g;
        if (u == t) cnt++;
        if (cnt == k) return tmp.g <= tt;
        for (int i = 0; i < G[u].size(); i++)
        {
            PII& e = G[u][i];
            int v = e.X, w = e.Y;
            q.push(HeapNode(v, g + w, g + w + d[v]));
        }
    }
    return false;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    int n, m;
    while (~scanf("%d%d", &n, &m))
    {
        init(n);
        int s, t, k, tt;
        scanf("%d%d%d%d", &s, &t, &k, &tt);
        s--, t--;
        while (m--)
        {
            static int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            u--, v--;
            add_edge(u, v, w);
        }
        spfa(t);
        if (A_star(s, t, k, tt))
            puts("yareyaredawa");
        else
            puts("Whitesnake!");
    }
    return 0;
}

A. Gudako and Ritsuka 
期望难度:Medium
考虑从后往前进行博弈动态规划,在这一过程中维护所有的先手必胜区间。区间不妨采用左开右闭,方便转移。
考虑一次转移,如果当前Servant的后一个位置属于对手,则当前Servant的必胜区间可以通过将后一个Servant的 每个必败区间的左端点+1、右端点+x得到;如果后一个位置属于自己,则可以通过将后一个Servant的必胜区间做 同样的操作得到。不妨分别对必胜区间左右端点维护一个偏移量,需要从对手进行转移时只需修改偏移量后交换左 右端点的集合,然后再在左端点的集合里插入一个0即可。
需要注意的是,这样得到的必胜区间会有重叠,可能导致对下一个对手的必胜区间的统计出错。考虑到每次转移时 所有的同类区间的长度的变化量都相同,可以分别用两个优先队列维护这两类区间,每次转移后暴力合并重叠的区 间即可。
 

F. Fantastic Graph 
期望难度:easy
添加源点s,汇点t。 对于原图的边,定义流量为[0,1],s对于N个点都连边,流量为[L,R],M个点对t都连边,流量为 [L,R]。那么就变成了有源汇上下界可行流问题。根据相关方法建图即可。 

 

你可能感兴趣的:(图论,网络流,博弈)