来源:codeforces Gym101666
思路:对于一个区间\([i,j]\)我们考虑固定右区间端点\(j\) ,我们记录以J为右端点的所有gcd的值,当我们考虑右端点为j+1的所有区间时,我们只需要考虑a[j]对于前一个区间的影响即可。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 5e5+5; typedef long long ll; ll gcd(ll a,ll b) {return b==0?a:gcd(b,a%b);} ll n; ll a[maxn],pre[maxn]; set<ll> ans; int main() { ios::sync_with_stdio(false); cin>>n; int cnt = 0; for(int i = 1;i <= n;i++) cin>>a[i]; for(int i = 1;i <= n;i++) { int len = cnt; for(int j = 0;j < len;j++) { ll t = gcd(pre[j],a[i]); pre[j] = t; } pre[cnt++] = a[i]; sort(pre,pre+cnt); cnt = unique(pre,pre+cnt) - pre; for(int k = 0;k < cnt;k++) ans.insert(pre[k]); } cout<<ans.size(); return 0; }题意:有n个点,编号为0到1,每个点有一个指示告知往哪个点走为0到1的一条最短路,现在要求找到一条从0到1的路径满足每次走都不遵循这个指示。
思路:从1做一次dij记录路径,这样就可以知道具体的告示,再从0做dfs记录路径看是否能到达1即可。
代码:
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; const int maxm = 1e6+5; const int INF = 5e5+5; struct Edge{ int u,v,w,next; Edge() {} Edge(int u,int v,int w,int next): u(u),v(v),w(w),next(next) {} }; int n,m; int head[maxn],d[maxn],path[maxn],ans[maxn],cnt = 0; bool vis[maxn],mark[maxn],ok = false; Edge G[maxm]; inline void AddEdge(int u,int v,int w) { G[++cnt] = Edge(u,v,w,head[u]); head[u] = cnt; } inline void dijkstra() { priority_queue<pair<int,int> > Q; for(int i = 0;i < n;i++) { d[i] = INF; vis[i] = false; } d[1] = 0; Q.push(make_pair(0,1)); while(!Q.empty()) { pair<int,int> f = Q.top();Q.pop(); int u = f.second; vis[u] = true; for(int i = head[u];i;i = G[i].next) { Edge e = G[i]; if(vis[e.v]) continue; if(d[e.v] > d[u] + e.w) { d[e.v] = d[u] + e.w; Q.push(make_pair(-d[e.v],e.v)); path[e.v] = u; } } } } void dfs(int u) { if(u == 1) { ok = true; return; } for(int i = head[u];i;i = G[i].next) { Edge e = G[i]; if(path[u] == e.v || mark[e.v]) continue; ans[u] = e.v; mark[e.v] = true; dfs(e.v); if(ok) return; } } int main() { scanf("%d%d",&n,&m); for(int i = 0;i < m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); AddEdge(u,v,w); AddEdge(v,u,w); } dijkstra(); memset(ans,-1,sizeof(ans)); dfs(0); if(ok) { vector<int> res; for(int i = 0;i != -1;i = ans[i]) res.push_back(i); printf("%d ",res.size()); for(int i = 0;i < res.size();i++) printf("%d ",res[i]); } else printf("impossible\n"); return 0; }思路:贪心
#include<bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); int n,a[16]; cin>>n; for(int i = 0;i < n;i++) cin>>a[i]; sort(a,a+n); int ans1 = 0,ans2 = 0; bool flag = 1; for(int i = n-1;i >= 0;i--) { if(flag) ans1+=a[i],flag = false; else ans2 += a[i],flag = true; } cout<<ans1<<" " << ans2; return 0; }题意:有m个人和n笔账单,要求最少通过几次转账才能还清。
思路:我们知道n个人最多可以通过n次转账来完成一次还清,而如果这n个人的盈亏总和为0,那么就可以减少一次操作,因此我们应该尽可能地去将这n个人分成多的盈亏总和为0的组。我们用\(f(t)\) 来表示当前状态\(t\) 的总盈亏,用\(dp[t]\) 来表示此状态的最大0分组个数,通过记忆化搜索更新值即可。
#include<bits/stdc++.h> using namespace std; const int maxm = 21; int s[maxm],n,m; int f[1<<maxm],dp[1<<maxm]; int dfs(int t) { if(~dp[t]) return dp[t]; if(f[t] == 0) { for(int i = 0;i < m;i++) { if(t&(1<<i)) return dp[t] = dfs(t-(1<<i))+1; } } else { for(int i = 0;i < m;i++) { if(t&(1<<i)) dp[t] = max(dp[t],dfs(t-(1<<i))); } } return dp[t]; } int main() { ios::sync_with_stdio(false); cin>>m>>n; for(int i = 0;i < n;i++) { int a,b,p; cin>>a>>b>>p; s[a]+=p; s[b]-=p; } for(int i = 0;i < (1<<m);i++) { dp[i] = -1; f[i] = 0; } for(int i = 0;i < (1<<m);i++) { for(int j = 0;j < m;j++) { if(i & (1<<j)) f[i] += s[j]; } } dp[0] = 0; cout<<m-dfs((1<<m)-1)<<endl; return 0; }思路:只需要从一个人到他能战胜的人连边,然后从0开始dfs看是否能够遍历所有点即可。
#include <bits/stdc++.h> using namespace std; int n; int a[1010][1010]; int used[1010]; int ans[1010]; char str[1010]; bool f; int t; void dfs(int u) { if(t==n-1) { f=1; return ; } for(int i=0; i<n; i++) if(a[u][i] && !used[i]) { used[i]=1; ans[t++]=i; dfs(i); } } int main() { scanf("%d",&n); f=0,t=0; memset(used,0,sizeof used); for(int i=0; i<n; i++) { scanf("%s",str); for(int j=0; j<n; j++) { if(str[j]=='X') a[i][j]=0; else if(str[j]=='1') a[i][j]=1; else a[i][j]=0; } } used[0]=1; dfs(0); if(f){ for(int i=t-1; i>=0; i--) printf("%d ",ans[i]); printf("0"); } else printf("impossible"); return 0; }思路:用map记录更新最佳的兑换比即可
#include<bits/stdc++.h> using namespace std; map<string,double> mp; int main() { ios::sync_with_stdio(false); mp["pink"] = 0.0; string s1,s2;double rate; int n; cin>>n; for(int i = 0;i < n;i++) { cin>>s1>>s2>>rate; if(!mp.count(s2)) continue; if(!mp.count(s1)) mp[s1] = mp[s2]+log10(rate); else mp[s1] = max(mp[s1],mp[s2] + log10(rate)); } double ans = mp["blue"]; if(ans > 1.0) printf("10.0\n"); else if(ans == 0) printf("0.0\n"); else printf("%.15lf\n",pow(10,ans)); return 0; }题意:再平面直角坐标上给出起点和终点,和一些得分点,要求从起点到终点只允许走最近的曼哈顿路径,要求怎么走可以得到最多的分。
思路:将各个得分点先按x再按y排序,本质上就是去求一个lis
#include<bits/stdc++.h> using namespace std; const int maxn = 1e5+5; struct Point{ int x,y; Point() {} Point(int x,int y): x(x),y(y) {} }; Point G[maxn]; int L[maxn],n; int cnt = 0; int lis() { L[0] = G[0].y; int len = 1; for(int i = 1;i < cnt;i++) { if(L[len - 1] <= G[i].y) L[len++] = G[i].y; else *upper_bound(L,L+len,G[i].y) = G[i].y; } return len; } bool cmp1(Point a,Point b) { if(a.x == b.x) return a.y < b.y; else return a.x < b.x; } bool cmp2(Point a,Point b) { if(a.x == b.x) return a.y < b.y; else return a.x > b.x; } int main() { ios::sync_with_stdio(false); int x1,y1,x2,y2; cin>>n>>x1>>y1>>x2>>y2; if(x1 > x2) { swap(x1,x2);swap(y1,y2); } int xl = min(x1,x2),xr = max(x1,x2),yd = min(y1,y2),yu = max(y1,y2); for(int i = 0;i < n;i++) { int x,y; cin>>x>>y; if(xl<=x&&x<=xr&&yd<=y&&y<=yu) G[cnt++] = Point(x,y); } if(!cnt) {printf("0\n");return 0;} if(y1 < y2) sort(G,G+cnt,cmp1); else sort(G,G+cnt,cmp2); printf("%d\n",lis()); return 0; }转载于:https://www.cnblogs.com/pot-a-to/p/11202069.html
相关资源:各显卡算力对照表!