有点,力不从心?
3888. 正确答案 (Standard IO)
考虑几种情况:
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 //
3889. 序列问题 (Standard IO)
首先看到题目没有其他方法解,可以考虑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 }
3890. 长途旅行 (Standard IO)
如何将一个大数据问题缩小规模?
在图论中,我们可以将它转化为最短路处理。
考虑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 "); 85 else if(spfa()){ 86 printf("Possible "); 87 } 88 else printf("Impossible "); 89 } 90 91 return 0; 92 }