atcoder绿题选做
ABC305:E https://atcoder.jp/contests/abc305/tasks/abc305_e
题意:给定一个无向图,给定k个守卫,每个守卫有h[i]的耐力值,如果是一个在图中是被保护的要满足和守卫的距离至少为h[i],让你升序打印所有被守卫的点
解题思路:可以从守卫出发,看守卫在可以走的情况下最远走到哪,最后统计被更新的点,核心做法是多源bfs和最短路的思想
1 #include<cstdio>//将每个点的守卫向外扩散,每次扩散消耗体力为1,如果体力为0则停止 2 #include<cstring>//最后统计被更新的点就可以,核心思想是多源bfs 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 const int N = 4e5+10; 31 int n,m,e[N],h[N],ne[N],idx,k; 32 bool vis[N]; 33 int dis[N]; 34 priority_queue<PII>q;//这里需要用大根堆,因为每次取堆头的都是剩余体力最大的 35 void add(int a,int b) 36 { 37 e[++idx]=b,ne[idx]=h[a],h[a]=idx; 38 } 39 void bfs() 40 { 41 memset(dis,-1,sizeof dis); 42 for(int i=1;i<=k;i++) 43 { 44 int a,b; 45 cin>>a>>b; 46 dis[a]=b; 47 q.push({b,a}); 48 } 49 while(!q.empty()) 50 { 51 auto tmp=q.top(); 52 q.pop(); 53 int d=tmp.first; 54 int x=tmp.second; 55 if(dis[x]>d) continue; 56 if(d) 57 //if(d<=0) continue; 58 { 59 for(int i=h[x];~i;i=ne[i]) 60 { 61 int y=e[i]; 62 if(dis[y]<d-1) 63 { 64 dis[y]=d-1; 65 q.push({d-1,y}); 66 } 67 } 68 } 69 } 70 } 71 signed main() 72 { 73 IOS; 74 memset(h,-1,sizeof h); 75 cin>>n>>m>>k; 76 for(int i=1;i<=m;i++) 77 { 78 int u,v; 79 cin>>u>>v; 80 add(u,v); 81 add(v,u); 82 } 83 bfs(); 84 vector<int>ans; 85 for(int i=1;i<=n;i++) 86 { 87 if(dis[i]>=0) ans.push_back(i); 88 } 89 cout<<ans.size()<<endl; 90 for(auto &it:ans) 91 { 92 cout<<it<<" "; 93 } 94 return 0; 95 }
ABC305:D https://atcoder.jp/contests/abc305/tasks/abc305_d
题意:高桥喜欢睡觉写日志,日志的长度为奇数且第奇数个元素代表他起床时刻,第偶数个元素代表他上床睡觉的时刻,现给定区间[l,r],询问在此区间内高桥的睡眠时间长为多少
解题思路:其实第一印象猜大概什么做法的话肯定是二分,因为要选择睡眠时间肯定是要找在a[i]内大于等于两个区间界限的时间点,,然后可能涉及到计算一段区间长度的问题,这里可以用前缀和来处理,然后就根据题意进行区间运算了
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 const int N = 2e5+10; 31 int n,a[N]; 32 int q,l,r; 33 int s[N]; 34 vector<int>gb; 35 vector<int>gu; 36 signed main() 37 { 38 IOS; 39 cin>>n; 40 for(int i=1;i<=n;i++) 41 { 42 cin>>a[i]; 43 s[i]=s[i-1]+(a[i]-a[i-1])*(i&1); 44 //cout<<s[i]<<" "; 45 } 46 cin>>q; 47 //cout<<endl; 48 while(q--) 49 { 50 int sum=0; 51 cin>>l>>r; 52 int id1=lower_bound(a+1,a+1+n,l)-a; 53 int id2=lower_bound(a+1,a+1+n,r)-a; 54 // if(id1>=n) 55 // { 56 // cout<<0<<endl; 57 // continue; 58 // } 59 // if(a[id1]%2==0&&a[id1-1]%2==0) 60 // { 61 // sum+=a[id1]-a[id1-1]; 62 // } 63 // for(int i=a[id1];i<=n&&a[i]<=r;i++) 64 // { 65 // if() 66 // } 67 sum=s[id2]-s[id1-1];//首先加上 a[posl]→a[posr]的睡眠分钟数 68 if(id1&1)//判断时间段l->a[posl]是否为睡眠时间 69 { 70 sum-=l-a[id1-1]; 71 } 72 if(id2&1)//判断是否是睡眠时间 73 { 74 sum-=a[id2]-r; 75 } 76 cout<<sum<<endl; 77 78 } 79 return 0; 80 }
ABC306D:https://atcoder.jp/contests/abc306/tasks/abc306_d
题意:给定n个菜,这些菜有一定的营养值且可能有毒1,可能无毒0,初始时候人的是健康的,如果他是在健康的状态下吃有毒的菜他会进入不健康状态,吃无毒的菜继续维持健康状态
如果他在不健康的状态下吃无毒的菜他会进入健康状态,反之他就挂了。
对于一些菜,这个人可以选择吃也可跳过,到最后如果i!=N再来一轮,i==N他会活着离开。
问此人在或者离开的情况下能获得最大的营养值是多少
tip:如果此人第一次吃到是有毒的菜那这一次菜的营养值不计入在内
解题思路:很典型的01背包,考虑在当前菜有毒/无毒情况下健康/不健康的进食获取值
1 #include<cstdio>//01背包问题 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define x first 24 #define y second 25 #define endl '\n' 26 #define inf LLONG_MAX 27 #define iinf INT_MAX 28 typedef pair<int,int> PII; 29 const double PI = acos(-1.0); 30 const double eps = 1e-6; 31 const int INF = 0x3f3f3f3f; 32 const int N = 3e5+10; 33 int n; 34 PII a[N]; 35 int nh=1; 36 bool vis[N]; 37 int dp[N][2]; 38 void init() 39 { 40 for(int i=1;i<=N;i++) 41 { 42 dp[i][0]=-inf; 43 } 44 } 45 signed main() 46 { 47 IOS; 48 cin>>n; 49 for(int i=1;i<=n;i++) 50 { 51 cin>>a[i].x>>a[i].y; 52 } 53 // sort(a+1,a+1+n,cmp); 54 // stack<pair<bool,int>>q; 55 // for(int i=1;i<=n;i++) 56 // { 57 // cout<<a[i].x<<" "<<a[i].y<<endl; 58 // } 59 // 60 // if(a[1].x) 61 // { 62 // nh--; 63 // } 64 // else 65 // { 66 // nh=1; 67 // } 68 // int sum=0; 69 // for(int i=2;i<=n;i++) 70 // { 71 // if(nh) 72 // { 73 // if(a[i].x) 74 // { 75 // nh--; 76 // sum+=a[i].y; 77 // } 78 // else 79 // { 80 // nh=1; 81 // sum+=a[i].y; 82 // } 83 // } 84 // else 85 // { 86 // if(a[i].x) 87 // { 88 // continue; 89 // } 90 // else 91 // { 92 // sum+=a[i].y; 93 // nh=1; 94 // } 95 // } 96 // } 97 // if(a[1].x) 98 // { 99 // q.push({1,a[1.y]}); 100 // } 101 // else 102 // { 103 // q.push({0,a[1].y}); 104 // } 105 // int sum=0; 106 // for(int i=2;i<=n;i++) 107 // { 108 // auto tmp=q.top(); 109 // if(tmp.x) 110 // { 111 // if(!a[i].x) 112 // { 113 // sum+=a[i].y; 114 // } 115 // } 116 // } 117 // cout<<max(0ll,sum)<<endl; 118 init(); 119 //dp[1][0]=-1; 120 for(int i=1;i<=n;i++) 121 { 122 if(a[i].x)//当前有毒 123 { 124 dp[i][1]=max(dp[i-1][1],dp[i-1][0]+a[i].y);//有毒的状态是从上一个有毒和上一个无毒且吃了当前 125 dp[i][0]=dp[i-1][0];//当前无毒则可以跳过不吃,因为值有可能变小 126 } 127 else//当前无毒 128 { 129 dp[i][1]=dp[i-1][1];//值可能变小,不吃 130 dp[i][0]=max({dp[i-1][0],dp[i-1][0]+a[i].y,dp[i-1][1]+a[i].y});//无毒的状态是从上一个无毒和上一个无毒且吃了当前还有上一个有毒 131 //但吃了无毒解毒了 132 } 133 } 134 cout<<max(dp[n][0],dp[n][1]); 135 return 0; 136 }
ABC297E:https://atcoder.jp/contests/abc297/tasks/abc297_e
题意:给定n个价值为a[i]的商品,要求你至少买一种且你被允许购买多个同类的商品,找到你可能支付的第k最低价格,在这里如果有多套价格相同的商品,价格只被计算一次
解题思路:可以考虑每次用当前集合中的最低价对其他元素进行累加同时删掉此元素,这样进行k次操作后取集合中最小的元素其实就是答案
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 const int N = 20; 31 const int M = 2e5+10; 32 int n,k; 33 int a[N]; 34 signed main() 35 { 36 IOS; 37 cin>>n>>k; 38 for(int i=1;i<=n;i++) cin>>a[i]; 39 set<int>s; 40 while(k--) 41 { 42 int tmp=*s.begin(); 43 s.erase(tmp); 44 //cout<<*s.begin()<<endl; 45 for(int j=1;j<=n;j++) 46 { 47 s.insert(a[j]+tmp); 48 } 49 } 50 cout<<*s.begin(); 51 return 0; 52 }
ABC290D:https://atcoder.jp/contests/abc290/tasks/abc290_d
题意:给定下标从0开始的n个格子,对每一个格子你可以进行这样的操作:
1.将当前格子涂为0
2.令x=(A+D)%N,A是当前格子的下标
3.如果格子x被标记了,那就重复(x+1)%N
4.涂下标为x的格子
解题思路:当时只觉得是模拟,但发现其实没这么简单,正确做法是裴蜀定理,下面给出此题的证明过程
首先有结论:设g = gcd(A,B) A = ag,B = bg 。
a项式子 0B mod A,Bmod A, 2B mod A,......(a - 1)Bmod A。
特点是:
1.每项式子的值都是g的倍数。
2.且倍数为0~ a―1每一个数恰好出现一次。
证明:
1. B mod A = B — xA(x= B /A)= bg — xag = (b - xa)g。2.设有重复的倍数iBmod A =jBmod A(i!= j)。
iB-jB=(i-j)bg = yA为A的倍数(iB― jB) mod A=0模A余数相同,那么相减后再模A余数自然为0。(i一 j)bg = yag
因为a与b互质( a与b若还有大于1的公约数,那么gcd就不会是g 而是g * gcd(a,b))。所以(i一j)是a的倍数这显然与上式系数区间[0, a―1]相违背。
此题对于上述定理的应用
设g= gcd(N, D) N =ng,D = dg。
对于上述问题有跳跃的前n步为0 mod N, D mod N, 2D mod N,.... , (n - 1)D mod N。每一项都是不重复的g 的倍数,所以不会触发条件2。而第n+1步nD mod N = ndg = dN mod N =0。
开始有重复项第二轮开始,此时需要向前走一步(0,接下来又可以按(Dmod N)+ 1,(2D mod N)+ 1,....的顺序进行n轮跳跃。
每一轮n个直到所有格子都被遍历到。所以我们只需要确定我们在哪一轮,偏移量+轮数即可轮数:len= (K- 1)/n。
偏移量:add= (K- 1) mod n。ans = add * D。
最初容易想到特殊情况,当D为N的因子时,前N/D步肯定没有重复,接下来每一步都是上一轮同样倍数+1若为0,3,6,9 . .....下一轮即为1,4,7,10 . . ....
随后再引申到非因子的数应该也有一个循环节上进行考虑。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 void solved() 31 { 32 int N,D,k; 33 cin>>N>>D>>k; 34 int g=__gcd(N,D); 35 int n=N/g; 36 int d=D/g; 37 int len=(k-1)/n; 38 int pos=(k-1)%n; 39 cout<<pos*D%N+len<<endl; 40 } 41 signed main() 42 { 43 IOS; 44 int t; 45 cin>>t; 46 while(t--) 47 { 48 solved(); 49 } 50 return 0; 51 }
ABC287E:https://atcoder.jp/contests/abc287/tasks/abc287_e
题意:给定n个字符串找出他们各自与其他字符串所具有的最大LCP值
LCP是指两个字符串的长度都大于等于i且在1~i直接具有相同的字符相匹配
解题思路:这不妥妥Trie?
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 const int N = 5e5+10; 31 int n; 32 string s[N]; 33 int trie[N][65]; 34 int num[N],idx=1; 35 int ctoi(char c) 36 { 37 int x; 38 if(c>='A'&&c<='Z') x=c-'A';//大写字母对应 0 ~ 25 39 else if(c>='a'&&c<='z') x=c-'a'+26;//小写字母对应 26 ~ 51,所以要减'a',再加上26 40 else x=c-'0'+52;//数字对应 52 ~ 61,同样的,减'0'再加上52 41 return x; 42 } 43 void insert(string t) 44 { 45 int p=0; 46 for(int i=0;t[i];i++) 47 { 48 int u=t[i]-'a'; 49 if(!trie[p][u]) trie[p][u]=idx++; 50 p=trie[p][u]; 51 num[p]++; 52 } 53 } 54 int query(string t) 55 { 56 int p=0; 57 int ans=0; 58 for(int i=0;t[i];i++) 59 { 60 int u=t[i]-'a'; 61 if(!trie[p][u]) return 0; 62 p=trie[p][u]; 63 if(num[p]==1) return ans; 64 ans++; 65 } 66 return ans; 67 } 68 signed main() 69 { 70 IOS; 71 cin>>n; 72 for(int i=1;i<=n;i++) 73 { 74 cin>>s[i]; 75 insert(s[i]); 76 } 77 for(int i=1;i<=n;i++) 78 { 79 cout<<query(s[i])<<endl; 80 } 81 return 0; 82 }
ABC284E:https://atcoder.jp/contests/abc284/tasks/abc284_e
题意:给定一个无向图找出它的简单路径的条数,然后输出min(ans,1e6)
解题思路:dfs回溯找路径比bfs更方便
1 #include<cstdio>//dfs即可 2 #include<cstring> 3 #include<algorithm> 4 #include<iostream> 5 #include<string> 6 #include<vector> 7 #include<stack> 8 #include<bitset> 9 #include<cstdlib> 10 #include<cmath> 11 #include<set> 12 #include<list> 13 #include<deque> 14 #include<map> 15 #include<queue> 16 #include <iomanip> 17 #include<ctime> 18 using namespace std; 19 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); 20 #define TLE (double)clock()/CLOCKS_PER_SEC<=0.95 21 #define int long long 22 #define double long double 23 #define endl '\n' 24 #define inf LLONG_MAX 25 #define iinf INT_MAX 26 typedef pair<int,int> PII; 27 const double PI = acos(-1.0); 28 const double eps = 1e-6; 29 const int INF = 0x3f3f3f3f; 30 const int N = 4e5+10; 31 int n,m,e[N],h[N],ne[N],idx,k; 32 bool vis[N]; 33 int cnt; 34 bool flag; 35 int tmp=1e6; 36 void add(int a,int b) 37 { 38 e[++idx]=b,ne[idx]=h[a],h[a]=idx; 39 } 40 // void bfs(int x) 41 // { 42 // queue<int>q; 43 // vis[x]=true; 44 // q.push(x); 45 // while(!q.empty()) 46 // { 47 // int x=q.front(); 48 // q.pop(); 49 // for(int i=h[x];~i;i=ne[i]) 50 // { 51 // int y=e[i]; 52 // if(!vis[y]) 53 // { 54 // q.push(y); 55 // } 56 // else cnt++; 57 // } 58 // } 59 // } 60 void dfs(int x) 61 { 62 if(cnt>=tmp) 63 { 64 flag=true; 65 return ; 66 } 67 vis[x]=true; 68 for(int i=h[x];~i;i=ne[i]) 69 { 70 int y=e[i]; 71 if(!vis[y]) 72 { 73 ++cnt; 74 dfs(y); 75 vis[y]=false; 76 } 77 } 78 } 79 signed main() 80 { 81 IOS; 82 memset(h,-1,sizeof h); 83 cin>>n>>m; 84 for(int i=1;i<=m;i++) 85 { 86 int u,v; 87 cin>>u>>v; 88 add(u,v); 89 add(v,u); 90 } 91 dfs(1); 92 if(!flag) 93 cout<<cnt+1<<endl; 94 else cout<<tmp; 95 // cout<<min(cnt+1,tmp)<<endl; 96 return 0; 97 }
本文来自博客园,作者:江上舟摇,转载请注明原文链接:https://www.cnblogs.com/LQS-blog/p/17545771.html