2016-11-14试题解题报告

2016-11-14试题解题报告

By shenben

T1

30%:  O(n ^ 2 * m)暴力判断。

100%: 很显然答案的可能性最多只有n种,所以我们将所有人的答案按字典序排序后枚举将每个人的答案作为正确答案来进行判断。

由于是判断题,若当前人的答案为正确答案则零分者的答案也就确定了,那么只需统计出这两种答案的人数判断是否满足题意即可。这一步使用字符串哈希即可解决。

 

 

T2:

30%:枚举每个数所在的集合或者不选,然后判定即可。复杂度O(n*3^n)

60% Dp,两个数相等就相当于两个数的xor0。设 f[i][j][k=0..2]代表 处理到第 I 个数,     如果 k = 1代表and值为j,如果k = 2代表xor 值为 j,如果k = 0则代表一个元素都没   取。所以很容易得到方程:

f[i][j][0] = f[i + 1][j][0]

f[i][j & ai][1] = f[i + 1][j][1] + f[i + 1][j][0] + f[i + 1][j & ai][1]

     f[i][j ^ ai][2] = f[i + 1][j][1] + f[i + 1][j][2] + f[i + 1][j ^ ai][2];

  最后f[1][0][2]就是答案, 复杂度为O(n * 1024 * 3)

  DP还可以分开用f[i][j]g[i][j]表示前ixor值为j,后iand值为j的方案数,     随后枚举分界点k来求总方案数。复杂度O(n * 1024 * 3)

100%:满分数据需要高精,答案位数较大,需要进行压位来防止TLE,因为不知道答案的     位数究竟多大,压位后高精数组仍需要开的较大一些,所以原DP的数组滚动即可。

 

 

T3

30%

T<= 10000的时候,可以设 vis[i][j] 代表到达第i个点时间为j是否合法。 这样是O(T*m),可以拿到小数据。

另外的那30%:各种奇怪的骗分方法。选手自行考虑。

100%

T很大的时候,我们考虑 如果0 -> x -> n - 1路径时间为T,且 x出发有一个时间为d的环,则 一定存在一个K满足 K + p*d = T(至少T满足条件),这样我们就能绕着环走p次就能构成一条时间为T的路径。

显然要求的路径一定经过 0,而且在合法情况下从0号点出发一定存在一条边,否则0号点和n - 1号就是不联通的。随便取一条边时间为d, 则能构成从0号点出发的一个时间为2d的环。这样原题就化为最短路问题了,dis[i][j] 代表到达i号点,时间为 j + p * 2d,最小的 j+p*2d

最后判断dis[n -1][T % 2d] 是否小于等于T即可。

实际上就是在30%的基础上缩减状态。

时间复杂度为O(m*d)

T1代码

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<vector>
#include<stack>
#include<queue>
#include<map>
using namespace std;
#define ll long long 
#define R register
#define debug(x) cout<<x<<"---"<<endl
inline int read(){
    R int x=0;bool f=1;
    R char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return f?x:-x;
} 
const int N=30000+5;
const int M=3000+5;
string s[N];
map<string,int>ys;
string s1,t;
int n,m,p,q;
int cnt,ans;
char ss[M];
int judge(string &std,string &now){
    int res=0;
    for(int i=0;i<m;i++) if(std[i]!=now[i]) res++;
    return res;
}
void fanzhuan(){
    for(int slen=s1.length(),i=0;i<slen;i++){
        s1[i]=(s1[i]=='N'?'Y':'N');
    }
    printf("%s",s1.c_str());
}
void sp(int x){
    if(x==m){
        int j,t;
        for(j=1;j<=cnt;j++){
            if(s[j]==s1) break;
            t=judge(s1,s[j]);
            if(t==m) break;
        }
        if(j>cnt){for(int i=0;i<m;i++) putchar(s1[i]);exit(0);}
        return ;
    }
    for(int i=0;i<2;i++){
        s1[x]=(!i?'N':'Y');
        sp(x+1);
    } 
}
void in(){
    char ch;int l=0;
    for(ch=getchar();l<m;ch=getchar()){
        if(ch!='
') ss[l++]=ch;
        else break;
    }
    ss[l]='