【纪中受难记】——C3D6: 卡手题

有点,力不从心?


Description

小H与小Y刚刚参加完UOIP外卡组的初赛,就迫不及待的跑出考场对答案。
“吔,我的答案和你都不一样!”,小Y说道,”我们去找神犇们问答案吧”。
外卡组试卷中共有m道判断题,小H与小Y一共从其他n个神犇那问了答案。之后又从小G那里得知,这n个神犇中有p个考了满分,q个考了零分,其他神犇不为满分或零分。这可让小Y与小H犯了难。你能帮助他们还原出标准答案吗?如有多解则输出字典序最小的那个。无解输出-1。
 

Input

第一行四个整数n, m, p, q,意义如上描述。
接下来n行,每一行m个字符’N’或’Y’,表示这题这个神犇的答案。

Output

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

Sample Input

2 2 2 0
YY
YY

Sample Output

YY
 

Data Constraint

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

考虑几种情况:

1. p,q均不为0:可以一个个查询字符串满足pq条件,取最小值。

2,p为0,q不为0或者pq都为0时,考虑未出现在给定字符串中的字符,即从最小字符开始往上枚举,找到可行解为止。

3.只有q为0时,和1类似。

推荐用哈希,我用的是multiset,t掉了

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #pragma GCC optimize(2)
  4 int read(){
  5     int x=0,f=1;
  6     char c=getchar();
  7     while(!isdigit(c)){
  8         if(c=='-') f=-1;
  9         c=getchar();
 10     }
 11     while(isdigit(c)){
 12         x=(x<<1)+(x<<3)+(c^48);
 13         c=getchar();
 14     }
 15     return x*f;
 16 }
 17 const int N=30010;
 18 int n,m,full,zero;
 19 multiset<string> q;
 20 string s[N];
 21 string ans;
 22 string rev(string t){
 23     for(int i=0;i<t.size();i++){
 24         if(t[i]=='N') t[i]='Y';
 25         else t[i]='N';
 26     }
 27     return t;
 28 }
 29 int main(){
 30     n=read();m=read();full=read();zero=read();
 31     if(full==0&&zero!=0){
 32         for(int i=1;i<=n;i++){
 33             cin>>s[i];
 34             q.insert(s[i]);
 35         }
 36         ans.assign(s[1]);
 37         for(int i=0;i<m;i++){
 38             ans[i]='N';
 39         }
 40         while(!(q.count(ans)==0&&q.count(rev(ans))==zero)){
 41             int i;
 42             for(i=m-1;i>=0;i--){
 43                 if(ans[i]=='N'){
 44                     ans[i]='Y';
 45                     break;
 46                 }
 47                 else ans[i]='N';
 48             }
 49             if(i==0){
 50                 printf("-1");
 51                 return 0;
 52             }
 53         }
 54         cout<<ans;
 55     }
 56     else if(full!=0&&zero==0){
 57         for(int i=1;i<=n;i++){
 58             cin>>s[i];
 59             q.insert(s[i]);
 60         }
 61         ans.assign(s[1]);
 62         for(int i=0;i<m;i++){
 63             ans[i]='Y';
 64         }
 65         sort(s+1,s+n+1);
 66         int siz=unique(s+1,s+n+1)-s-1;
 67         int flag=0;
 68         for(int i=1;i<=siz;i++){
 69             if(q.count(s[i])==full&&q.find(rev(s[i]))==q.end()){
 70                 ans=min(ans,s[i]);
 71                 flag=1;
 72             }
 73         }
 74         if(!flag){
 75             printf("-1");
 76         }
 77         else cout<<ans;
 78     }
 79     else if(full==0&&zero==0){
 80         for(int i=1;i<=n;i++){
 81             cin>>s[i];
 82             q.insert(s[i]);
 83         }
 84         ans.assign(s[1]);
 85         for(int i=0;i<m;i++){
 86             ans[i]='N';
 87         }
 88         while(q.count(ans)!=0||q.count(rev(ans))!=0){
 89             int i;
 90             for(i=m-1;i>=0;i--){
 91                 if(ans[i]=='N'){
 92                     ans[i]='Y';
 93                     break;
 94                 }
 95                 else ans[i]='N';
 96             }
 97             if(i==0){
 98                 printf("-1");
 99                 return 0;
100             }
101         }
102         cout<<ans;
103     }
104     else{
105         for(int i=1;i<=n;i++){
106             cin>>s[i];
107             q.insert(s[i]);
108         }
109         ans.assign(s[1]);
110         for(int i=0;i<m;i++){
111             ans[i]='Y';
112         }
113         sort(s+1,s+n+1);
114         int siz=unique(s+1,s+n+1)-s-1;
115         int flag=0;
116         for(int i=1;i<=siz;i++){
117             if(q.count(s[i])==full&&q.count(rev(s[i]))==zero){
118                 ans=min(ans,s[i]);
119                 flag=1;
120             }
121         }
122         if(!flag){
123             printf("-1");
124         }
125         else cout<<ans;
126     }
127     return 0;
128 }
129 //find =end no
130 //

Description

小H是个善于思考的学生,她正在思考一个有关序列的问题。
她的面前浮现出了一个长度为n的序列{ai},她想找出两个非空的集合S、T。
这两个集合要满足以下的条件:
两个集合中的元素都为整数,且都在 [1, n] 里,即Si,Ti ∈ [1, n]。
对于集合S中任意一个元素x,集合T中任意一个元素y,满足x < y。
对于大小分别为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),你能帮助她吗?
 

Input

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

Output

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

Sample Input


1 2 3 3

Sample Output

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 
 

Data Constraint

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

首先看到题目没有其他方法解,可以考虑dp。

发现&和^有个区别:

a^b=c能得到a^c=b,调换等式成立,而a&b=c不能得到a&c=b,这启发我们结论具有单向性。

因此考虑从&到^处理。

用f[i][j][0/1/2]表示以i点为界,1~i组成s序列,i+1~n组成t序列的方案数,0/1/2分别表示这个点不选/给s/给t

那么转移式子有三个:

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

f[i][j][1]=f[i+1][j][0]+f[i+1][j][1]+f[i+1][j&a[i+1]][1];

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

考虑and的性质,如果给个0给他,那么后面都是0了,因此要给所有位置附上1,由于数据范围<=1024,那就给1023吧。

fp[0][1023][0]=1;

就可以dp了。

代码一开始用vector写的,后来t了。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 int read(){
  4     int x=0,f=1;
  5     char c=getchar();
  6     while(!isdigit(c)){
  7         if(c=='-') f=-1;
  8         c=getchar();
  9     }
 10     while(isdigit(c)){
 11         x=(x<<1)+(x<<3)+(c^48);
 12         c=getchar();
 13     }
 14     return x*f;
 15 }
 16 const int N=2e3+10;
 17 const int W=1e9;
 18 //struct bigint{
 19 //    vector<int> s;
 20 //    bigint(long long a=0){
 21 //        *this=a;
 22 //    }
 23 //    bigint operator =(long long a){
 24 //        s.clear();
 25 //        while(a){
 26 //            s.push_back(a%mod);
 27 //            a/=mod;
 28 //        }
 29 //        return *this;
 30 //    }
 31 //    bigint operator +(bigint &b){
 32 //        bigint c;
 33 //        c.s.clear();
 34 //        for(int i=0,g=0;;i++){
 35 //            if(g==0&&i>=s.size()&&i>=b.s.size()) break;
 36 //            int x=g;
 37 //            if(i<s.size()) x+=s[i];
 38 //            if(i<b.s.size()) x+=b.s[i];
 39 //            c.s.push_back(x%mod);
 40 //            g=x/mod;
 41 //        }
 42 //        return c;
 43 //    }
 44 //    void print(){
 45 //        for(int i=s.size()-1;i>=0;i--){
 46 //            printf("%d",s[i]);
 47 //        }
 48 //    }
 49 //}f[2][N][3];
 50 struct node{
 51     int len,a[40];
 52     node():len(1){memset(a,0,sizeof(a));}
 53     inline void operator+=(node &b)
 54     {
 55         b.len>len?len=b.len:0;
 56         for (int i=1;i<=len;i++) {
 57             a[i]+=b.a[i];
 58             if (a[i]>=W) a[i+1]++,a[i]-=W;
 59         }
 60         if (a[len+1])len++;
 61         return ;
 62     }
 63     inline void print()
 64     {
 65         printf("%d",a[len]);
 66         for (int i=len-1;i;i--)
 67             printf("%09d",a[i]);
 68         return;
 69     }
 70 }f[2][1025][3];
 71 int n;
 72 int p[N];
 73 int main(){
 74     n=read();
 75     for(int i=n;i>=1;i--) p[i]=read();
 76     f[0][1023][0].a[1]=1;
 77 //    for(int i=0;i<n;i++){
 78 //        for(int j=0;j<=1023;j++){
 79 //            for(int k=0;k<=2;k++){
 80 //                f[p][j][k]=f[p^1][j][k];
 81 //            }
 82 //        }
 83 //        for(int j=0;j<=1023;j++){
 84 //            f[p][j&a[i+1]][1]=f[p][j&a[i+1]][1]+f[p^1][j][1]+f[p^1][j][0];
 85 //            f[p][j^a[i+1]][2]=f[p][j^a[i+1]][2]+f[p^1][j][1]+f[p^1][j][2];
 86 //        }
 87 //        p^=1;
 88 //    }
 89 //    printf("%d",f[p][0][2]);
 90 ////    f[p][0][2].print();
 91     int pre=0,suc=1,m=1024;
 92     for (int i=0;i<n;i++){
 93          suc=pre^1;
 94           for(int j=0;j<m;j++)
 95             for (int k=0;k<=2;k++)
 96                 f[suc][j][k]=f[pre][j][k];
 97         for (int j=0;j<m;j++)
 98         {
 99             int a=p[i+1]&j,x=p[i+1]^j;
100             f[suc][a][1]+=f[pre][j][0]; f[suc][a][1]+=f[pre][j][1]; 
101             f[suc][x][2]+=f[pre][j][1]; f[suc][x][2]+=f[pre][j][2];
102         }
103         pre=suc;
104     }
105     f[pre][0][2].print();    
106     return 0;
107 }

Description

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”。(不含引号)。
 

Input

第一行一个正整数Case,表示数据组数。
每组数据第一行3个整数,分别为n, m, T。
接下来m行,每行3个整数x, y, z,代表城市x和城市y之间有一条耗时为z的双向边。

Output

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

Sample Input

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

Sample Output

Possible
Impossible
【样例解释】
第一组:0 -> 1 -> 2 :11
第二组:显然偶数时间都是不可能的。
 

Data Constraint

30%:  T <= 10000 
另有30%: n <= 5 , m <= 10.
100%: 2 <= n <= 50 , 1 <= m <= 100 , 1 <= z <= 10000 , 1 <= T <= 10^18 , Case <= 5.

如何将一个大数据问题缩小规模?

在图论中,我们可以将它转化为最短路处理。

考虑f[i][j]表示0~i点有一段路径为j。

值代表什么先放一边,我们考虑在0->x->n-1的路径上有一个长度为d的环,我们一定可以绕它p次,即消耗p*d的时间,如果此时我们到n-1的路径长度为k,一定存在某一种情况使得k+p*d=T,这样就相当于在环上走了p圈。

我们把问题规模缩小,从0出发到某个相邻的点,这段路径为d,如果我们绕着它走,相当于消耗了2*p*d的时间,假定有某种情况,路径长为k,一定可以看做在别的地方走了k%2d,剩下的路在d上来回走得到的。

意思就是,将路径的所有距离全部模2d再处理问题。

f[i][j]此时就是时间为j+2pd时最小的j+2pd。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 ll read(){
 5     ll x=0,f=1;
 6     char c=getchar();
 7     while(!isdigit(c)){
 8         if(c=='-') f=-1;
 9         c=getchar();
10     }
11     while(isdigit(c)){
12         x=(x<<1)+(x<<3)+(c^48);
13         c=getchar();
14     }
15     return x*f;
16 }
17 const ll inf=1e18;
18 const int N=60;
19 int n,m,p;
20 ll T;
21 ll f[55][20010];
22 ll dis[N][20010];
23 struct edge{
24     int to,next,w;
25 }e[N<<1];
26 int head[N<<1],cnt;
27 void addedge(int from,int to,int w){
28     e[++cnt]=(edge){to,head[from],w};
29     head[from]=cnt;
30 }
31 struct node{
32     int pos,dis;
33 };
34 queue<node> q;
35 int vis[N][20010];
36 bool spfa(){
37     for(int i=0;i<=n;i++){
38         for(int j=0;j<=p;j++){
39             dis[i][j]=inf;
40             vis[i][j]=0;
41         }
42     }
43     dis[1][0]=0;
44     q.push((node){1,0});
45     vis[1][0]=1;
46     while(!q.empty()){
47         node tmp=q.front();
48         q.pop();
49         vis[tmp.pos][tmp.dis]=0;
50         ll u=tmp.pos,w1=tmp.dis;
51         for(int i=head[u];i;i=e[i].next){
52             ll v=e[i].to;
53             ll w2=e[i].w;
54             ll w=(w1+w2)%p;
55             if(dis[u][w1]+w2<dis[v][w]){
56                 dis[v][w]=dis[u][w1]+w2;
57                 if(!vis[v][w]){
58                     q.push((node){v,w});
59                     vis[v][w]=1;
60                 }
61             }
62         }
63     }
64     return dis[n][T%p]<=T;
65 }
66 int M;
67 int main(){
68     M=read();
69     while(M--){
70         n=read(),m=read(),T=read();
71         p=200010;
72         cnt=0;
73         memset(head,0,sizeof(head));
74         memset(e,0,sizeof(e));
75         for(int i=1,x,y,z;i<=m;i++){
76             x=read();y=read();z=read();
77             x++,y++;
78             addedge(x,y,z);
79             addedge(y,x,z);
80             if(x==1||y==1){
81                 p=min(z*2,p);
82             }
83         }
84         if(p==200010) printf("Impossible\n");
85         else if(spfa()){
86             printf("Possible\n");
87         }
88         else printf("Impossible\n");
89     }
90     
91     return 0;
92 }

猜你喜欢

转载自www.cnblogs.com/Nelson992770019/p/11838570.html