标签:题目 bit lse 个数 重复 AC 删除 dfs line
随便看了一场以前的bestcoder,然后顺便写了一下,都不码的样子
有中文题面,这里就不写题目大意了
T1.
刚开始想复杂了,T1可能是4道题里面想的最久的
我们大概弄一下就可以发现,如果a[i]>0,并且a[i+1]满足条件,那么s[i]=s[i+1]
所以我们发现其实是一堆相同的弄在一起。
当然如果a[i]=0那么说明s[i]!=s[i-1],这样i就有25种选法,刚开始有26种选法
就是ans=26*25^(a[i]==0的个数)
我们考虑什么时候答案=0,显然a[i]!=0&&a[i]!=a[i+1]+1那么就不合法了
代码:
#include<bits/stdc++.h> #define N 2000005 #define Mod 1000000007 using namespace std; int n,T,ans,a[N]; int main(){ scanf("%d",&T); while (T--){ scanf("%d",&n);n--;ans=26; for (int i=1;i<=n;i++) scanf("%d",&a[i]);a[n+1]=0; for (int i=1;i<=n;i++) if (a[i]!=a[i+1]+1&&a[i]!=0) ans=0; for (int i=1;i<=n;i++) if (!a[i]) ans=1ll*ans*25%Mod; printf("%d\n",ans); } return 0; }
T2.
因为只有3条边,显然不会重复走,最短路一定是正常走+走加入的三条路
那么只要枚举一下3条路的排列,然后方向判断一下,dfs就ok了
代码:
#include<bits/stdc++.h> #define N 500005 #define Mod 1000000007 using namespace std; int T,n,m,a[N],b[N],s,t,ans,sum;bool use[5]; void dfs(int now,int tot){ if (tot+abs(now-t)<ans) ans=tot+abs(now-t); for (int i=1;i<=3;i++){ if (use[i]) continue; use[i]=1; dfs(a[i],tot+1+abs(now-b[i])); dfs(b[i],tot+1+abs(now-a[i])); use[i]=0; } } int main(){ scanf("%d",&T); while (T--){ scanf("%d%d",&n,&m); for (int i=1;i<=3;i++) scanf("%d%d",&a[i],&b[i]); for (int i=1;i<=m;i++){ ans=1e9;scanf("%d%d",&s,&t); dfs(s,0); sum=(sum+1ll*i*ans%Mod)%Mod; } printf("%d\n",sum);sum=0; } return 0; }
T3.
对于第一个操作,其实等价于xor一个2^x
其实原问题等价于求0-->S^T的最少操作次数
我们发现n<=15,所以我们对于a[i]暴力dfs求出用这些数组成的数的最小次数
dp[i]表示构成i的最小次数
然后考虑操作1
因为都是xor一个2的次方数,所以每一位都是相互独立的
如果x^3是最优的,那么x^1一定是最优的,然后x^1^2也随之一定是最优的
所以我们把x从0到15枚举一下
然后再枚举i的值,更新一下dp值即可
一般的位运算的题,都是先枚举次方再枚举i的
代码:
#include<bits/stdc++.h> #define N 1000005 #define Mod 1000000007 using namespace std; int T,n,m,s,t,ans,a[N],mp[N]; void dfs(int u,int dep,int sum){ if (mp[sum]>dep) mp[sum]=dep; if (u==n+1) return; dfs(u+1,dep+1,sum^a[u]); dfs(u+1,dep,sum); } int main(){ scanf("%d",&T); while (T--){ scanf("%d%d",&n,&m); memset(mp,127,sizeof(mp)); for (int i=1;i<=n;i++) scanf("%d",&a[i]); dfs(1,0,0); for (int j=0;j<=17;j++) for (int i=0;i<=(1<<18);i++) if (mp[i^(1<<j)]>mp[i]+1) mp[i^(1<<j)]=mp[i]+1; for (int i=1;i<=m;i++){ scanf("%d%d",&s,&t); //cerr<<mp[s^t]<<endl; ans=(ans+1ll*mp[s^t]*i%Mod)%Mod; } printf("%d\n",ans);ans=0; } return 0; }
T4.
感觉T2-T4都没啥难度,还是T1最难(┭┮﹏┭┮)<----弱
显然的贪心,如果当前剩下的点中最小的点能够通过删边来得到,那么就删那个条数
注意我们不用考虑删的是哪些边
因为这个点拓扑了,那么意味着从它出发的边都要删除,所以不用知道具体哪些,只要知道这个点是不是要删即可
然后用一个堆来维护一下点的大小值即可
代码:
#include<bits/stdc++.h> #define N 2000005 #define Mod 1000000007 using namespace std; int n,m,k,T,x,y,kk,head[N],ru[N];bool use[N],flag[N]; struct Edge{int nxt,to;}e[N]; priority_queue<int,vector<int>,greater<int> > Q; inline void link(int x,int y){e[++kk].nxt=head[x];e[kk].to=y;head[x]=kk;} int main(){ scanf("%d",&T); while (T--){ scanf("%d%d%d",&n,&m,&k); memset(ru,0,sizeof(ru)); kk=0;memset(head,0,sizeof(head)); while (!Q.empty()) Q.pop(); for (int i=1;i<=m;i++){ scanf("%d%d",&x,&y); link(x,y);ru[y]++; } for (int i=1;i<=n;i++){ if (ru[i]<=k) Q.push(i),flag[i]=0; else flag[i]=1; } long long ans=0,tot=0; while (!Q.empty()){ while (ru[Q.top()]>k){flag[Q.top()]=1;Q.pop();} int x=Q.top();int y=ru[x]; //printf("WTF%d\n",x); ru[x]=0;k-=y; Q.pop();ans=(ans+1ll*(++tot)*x%Mod)%Mod; for (int i=head[x];i;i=e[i].nxt){ int v=e[i].to; if (ru[v]<=k+1&&ru[v]>0&&flag[v]){flag[v]=0;Q.push(v);} ru[v]--; } } printf("%lld\n",ans); } return 0; }
标签:题目 bit lse 个数 重复 AC 删除 dfs line
原文地址:https://www.cnblogs.com/ckr1225/p/9033220.html