2017-7-14测试

问题 A: 正确答案

时间限制: 2 Sec  内存限制: 256 MB
提交: 665  解决: 76
[提交][状态][讨论版]

题目描述

小H与小Y刚刚参加完UOIP外卡组的初赛,就迫不及待的跑出考场对答案。

“吔,我的答案和你都不一样!”,小Y说道,”我们去找神犇们问答案吧”。

外卡组试卷中共有m道判断题,小H与小Y一共从其他n个神犇那问了答案。之后又从小G那里得知,这n个神犇中有p个考了满分,q个考了零分,其他神犇不为满分或零分。这可让小Y与小H犯了难。你能帮助他们还原出标准答案吗?如有多解则输出字典序最小的那个。无解输出-1。

输入

第一行四个整数n, m, p, q,意义如上描述。

接下来n行,每一行m个字符’N’或’Y’,表示这题这个神犇的答案。

输出

仅一行,一个长度为m的字符串或是-1。

样例输入

2 2 2 0 YY YY

样例输出

YY

提示

"Times New Roman";mso-hansi-font-family:"Times New Roman"">【数据范围】

30% : n <= 100.

60% : n <= 5000 , m <= 100.

100% : 1 <= n <= 30000 , 1 <= m <= 500. 0 <= p , q.  p + q <= n.

此题思路很容易,但是c++我纠结于如何读入一个string类的字符串,pascal又不会手写map。最后发现其实c++可以直接用map标记string

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<map>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
map<string,int>Z,F;
map<string,int>::iterator it;
int n,m,p,q,num;
    char ST[510],IST[510],ans[510];
bool pl(){
    int point=m-1;
    while (ST[point]=='Y') {
        if (point==0) return false;
        ST[point]='N',point--;
    }
    ST[point]='Y';
    return true;
}

int main(){
    scanf("%d%d%d%d",&n,&m,&p,&q);

    for(int i=1;i<=n;i++){
        scanf("%s",ST);
        for(int j=0;j<m;j++)
            ST[j]=='Y'?IST[j]='N':IST[j]='Y';
        Z[ST]++;
        //cout<<IST<<endl;
        F[IST]++;
    }
    it=Z.begin();
    string st;
    string data;
    bool firstans=true;
    if ((p==0)&&(q==0)){
        for(int j=0;j<m;j++)ST[j]='N';
        do{
            //cout<<ST;
            if ((Z[ST]==0)&&(F[ST]==0)){
                cout<<ST;
                return 0;
            }
        }while(pl());
        cout<<-1;
        return 0;
    }
    while(it!=Z.end()){
        num=it->second;
        //printf("%d
",num);
        if (num!=p) {
            it++;
            continue;
        }
        st=it->first;
        //cout<<st<<en6dl;
        num=F[st];
        if (num!=q) {
            it++;
            continue;
        }
        if ((firstans)||(st<data))
            firstans=false,data=st;
        it++;
    }
    /*
    it=F.begin();
    while(it!=F.end()){
        num=it->second;
        if (num!=q) {
            it++;
            continue;
        }
        st=it->first;
        //cout<<st<<endl;
        num=Z[st];
        if (num!=p) {
            it++;
            continue;
        }
        if ((firstans)||(st<data))
            firstans=false,data=st;
        it++;
    }*/
    if (firstans) cout<<-1; else cout<<data;
}
View Code

序列问题

时间限制: 1 Sec  内存限制: 256 MB
提交: 340  解决: 29
[提交][状态][讨论版]

题目描述

小H是个善于思考的学生,她正在思考一个有关序列的问题。

她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。

这两个集合要满足以下的条件:

1. 两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。

2. 对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。

3. 对于大小分别为p, q的集合S与T,满足

            a[s1] xor a[s2] xor a[s3] ... xor a[sp] = a[t1] and a[t2] and a[t3] ... and a[tq].

小H想知道一共有多少对这样的集合(S,T),你能帮助她吗?

输入

第一行,一个整数n

       第二行,n个整数,代表ai。

输出

仅一行,表示最后的答案。

样例输入

4 1 2 3 3

样例输出

4

提示

【样例解释】

S = {1,2}, T = {3}, 1 ^ 2 = 3 = 3 (^为异或)

S = {1,2}, T = {4}, 1 ^ 2 = 3 = 3

S = {1,2}, T = {3,4} 1 ^ 2 = 3 & 3 = 3 (&为与运算)

S = {3}, T = {4} 3 = 3 = 3


【数据范围】


    30%: 1 <= n <= 10


    60%: 1 <= n <= 100


    100%: 1 <= n <= 1000, 0 <= ai < 1024

一开始以为爆搜能拿30分——开心,后来爆弹(气死了),后来发现hzw的搜索代码也是0分——开心。

其实这道题的DP很好想。

F[i][j]表示前i个数(第i个数一定要取)亦或值为j的方案数。

但这样转移的时候要同时枚举j,k。时间复杂度n^2*1024;

其实我们可以加个辅助数组,f[i][j]表示前i个数(第i个数不一定要取的方案数)这样就可以直接转移啦。(其实求答案时的时间复杂度还是n^2*1024);

最后这道题要开高精度+压位

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 1110
#define ll long long 
using namespace std;
ll f[maxn][maxn],F[maxn][maxn],g[maxn][maxn],G[maxn][maxn],n,a[maxn],ans;
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++)
    scanf("%lld",&a[i]);
    //f[i] means the number of ways to choose  when i needn't to be choosen but F[i] means i must to be choosen
    //g is same as f
    for(ll i=1;i<=n;i++)
    {
        f[i][a[i]]++;
        F[i][a[i]]++;
        for(ll k=0;k<1024;k++)
            f[i][k]+=f[i-1][k];
        for(ll k=0;k<1024;k++)
            f[i][a[i]^k]+=f[i-1][k],F[i][a[i]^k]+=f[i-1][k];
    }
    for(ll i=n;i>=1;i--)
    {
        g[i][a[i]]++;
        G[i][a[i]]++;
        for(ll k=0;k<1024;k++)
            g[i][k]+=g[i+1][k];
        for(ll k=0;k<1024;k++)
             g[i][a[i]&k]+=g[i+1][k],G[i][a[i]&k]+=g[i+1][k];    
    }
    for(ll i=1;i<=n;i++)
        for(ll k=i+1;k<=n;k++)
        //if(a[i]<a[k])
        {
            for(ll j=0;j<1024;j++)
            ans+=F[i][j]*G[k][j];
        }
    printf("%lld
",ans);    
    
}

问题 C: 长途旅行

时间限制: 1 Sec  内存限制: 256 MB
提交: 285  解决: 48
[提交][状态][讨论版]

题目描述

JY是一个爱旅游的探险家,也是一名强迫症患者。现在JY想要在C国进行一次长途旅行,C国拥有n个城市(编号为0,1,2...,n - 1),城市之间有m条道路,可能某个城市到自己有一条道路,也有可能两个城市之间有多条道路,通过每条道路都要花费一些时间。JY从0号城市开始出发,目的地为n – 1号城市。由于JY想要好好参观一下C国,所以JY想要旅行恰好T小时。为了让自己的旅行更有意思,JY决定不在任何一个时刻停留(走一条到城市自己的路并不算停留)。JY想知道是否能够花恰好T小时到达n – 1号城市(每个城市可经过多次)。现在这个问题交给了你。

若可以恰好到达输出“Possible”否则输出“Impossible”。(不含引号)。

输入

第一行一个正整数Case,表示数据组数。

       每组数据第一行3个整数,分别为n, m, T。

       接下来m行,每行3个整数x, y, z,代表城市x和城市y之间有一条耗时为z的双向边。

输出

对于每组数据输出”Possible”或者”Impossible”.

样例输入

2
3 3 11
0 2 7
0 1 6
1 2 5
2 1 10000
1 0 1

样例输出

Possible
Impossible

提示

       30%:  T <= 10000


另有30%: n <= 5 , m <= 10 , Case <= 5.


       100%: 2 <= n <= 50, 1 <= m <= 100, 1 <= z <= 10000, 1 <= T <= 10^18, Case <= 15.

这道题考试的时候想到了用f[i][j]表示到达i点用j时间的可行性,但是T实在太大。因为出发点肯定连着至少一条边。因为T很大,所以必定有很多浪费的时间(即去一个已经走过的城市),我们把这些浪费的时间全部用在走与原点相邻的一条边上(走来走去),然后可以发现只要是这条边长*2的整数倍的时间都可以浪费掉。令dis[i][j]表示到达第i个点,所花的总时间模上两倍的第一条边的边长是j时的最少花费时间。

比较感性的理解一下就是到达第i个点的时间如果比T大或者=NIL,就不行。如果存在一种方案使得花费时间%2*p=T%2p且小于T,就可以走到了

hgz的代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <queue>

using namespace std;
typedef long long ll;

struct PATH
{
    int dis, to;
};

struct NODE
{
    int s, t;
};

vector<PATH> path[1010];

ll dis[55][20005];
int cnt, s, k, a, b, c, n, m, i, mod, t;
ll T;
void spfa()
{
    memset(dis, 0x7f7f7f7f, sizeof(dis));
    Queue<NODE> Q1;
    Q1.push((NODE){s, 0});
    dis[s][0] = 0;
    while (!Q1.empty())
    {
        NODE tmp = Q1.front();
        Q1.pop();
        int u = tmp.s;
        for (int i = 0; i < path[u].size(); i++)
        {
            int goton = path[u][i].to;  
            int t2 = (tmp.t + path[u][i].dis) % mod;
            if (dis[goton][t2] > dis[u][tmp.t] + path[u][i].dis)
            {
                dis[goton][t2]=dis[u][tmp.t]+path[u][i].dis;
                Q1.push((NODE){goton,t2});
            }
        }
    }
}

void addpath(int a, int b, int c)
{
    PATH tmp;
    tmp.to = b;
    tmp.dis = c;
    path[a].push_back(tmp);
    if ((a == 1) && (c < mod))
        mod = c;
}

int main()
{
    scanf("%d", &t);
    while (t--)
    {
        for (int i = 1; i <= n; i++)
        {
            path[i].clear();
        }
        mod = 0x7f7f7f7f;
        scanf("%d%d%lld", &n, &m, &T);
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d%d", &a, &b, &c);
            a++, b++;
            addpath(a, b, c);
            addpath(b, a, c);
        }
        if (mod == 0x7f7f7f7f)
            printf("Impossible
");
        else
        {
            mod *= 2;
            s = 1;
            spfa();
            if (dis[n][T % mod] <= T)
                printf("Possible
");
            else
                printf("Impossible
");
        }
    }
    system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/dancer16/p/7182249.html