水题:代码例如以下
#include <bits/stdc++.h> #define foreach(it,v) for(__typeof(v.begin()) it = v.begin(); it != v.end(); ++it) using namespace std; const int maxn = 2e5; int a[maxn]; int main(int argc, char const *argv[]) { ios_base::sync_with_stdio(false); int n,w[3][2]; while(cin>>n) { for(int i = 0; i < 3; i++) cin>>w[i][0]>>w[i][1]; int a[3]; int limt = w[1][0] + w[2][0]; a[0] = min(w[0][1],n - limt); n -= a[0]; limt = w[2][0]; a[1] = min(w[1][1],n - limt); n -= a[1]; a[2] = min(n,w[2][1]); printf("%d %d %d\n", a[0],a[1],a[2]); } return 0; }
#include <bits/stdc++.h> #define foreach(it,v) for(__typeof(v.begin()) it = v.begin(); it != v.end(); ++it) using namespace std; const int maxn = 2e5; int a[maxn]; int main(int argc, char const *argv[]) { ios_base::sync_with_stdio(false); int n,w; while(cin>>n>>w) { for(int i = 1; i <= n+n; i++) { cin>>a[i]; } sort(a+1,a+1+n+n); double M = a[n + 1] / 2.0; M = min(M,a[1]*1.0); double ans = M * n + 2*M*n; if(ans > w) ans = w; printf("%.10f\n", ans); } return 0; }
枚举最高的那个脚的高度H。大于H的直接删掉(后缀和记录代价即可),设高度为H的有x根,小于H的有y根。那么我们必须删掉k = max(y-(x-1),0)根,本题d值较小开个cnt数组记录下即可,假设比較大的话能够用平衡树维护前k小的代价和。
#include <bits/stdc++.h> #define foreach(it,v) for(__typeof(v.begin()) it = v.begin(); it != v.end(); ++it) using namespace std; const int maxn = 2e5; int l[maxn],d[maxn]; vector<int> g[maxn]; int s[maxn]; int main(int argc, char const *argv[]) { ios_base::sync_with_stdio(false); int n; while(cin>>n) { for(int i = 0; i <= 100001; i++) { s[i] = 0; g[i].clear(); } for(int i = 1; i <= n; i++) cin>>l[i]; for(int i = 1; i <= n; i++) { int x;cin>>x; g[l[i]].push_back(x); s[l[i]] +=x; } vector<int> t; for(int i = 100000; i >= 0; i--) s[i] += s[i+1]; for(int i = 0; i <= 100000; i++)if(g[i].size()){ t.push_back(i); } int cost = 1e8,sum = 0; int cnt[205]; memset(cnt,0,sizeof cnt); foreach(id,t) { int & x = *id; int w = s[x+1] - s[100001]; int sz = g[x].size(); int d = sz - 1; d = max(sum-d,0); int i; for(i = 0; i <= 200; i++) { d -= cnt[i]; w += i*cnt[i]; if(d <= 0) break; } w += d*i; cost = min(cost,w); sum += g[x].size(); foreach(it,g[x]) { ++cnt[*it]; } } printf("%d\n", cost); } return 0; }
首先假设有0条边那么任选3个点就能构成奇环。答案是3 c(n,3)
假设每一个节点最多仅仅有一条边与其关联且m > 0,那么对于每条边(u,v),任选节点k。仅仅须要加入两条边就能构成奇环。答案是2,m*(n-2)。
假设存在节点的度大于2,那么推断是否是否是二分图。假设不是意味着已经存在奇环,答案是 0,1
否则对每一个联通分量仅仅须要在同色节点里任选两个加边就能形成奇环,答案是1,,sum(c(ci[0],2)+c(ci[1],2));
盗用Quailty的代码QAQ......
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<iostream> #include<algorithm> #include<vector> #include<queue> using namespace std; typedef long long ll; vector<int>e[100005]; int vis[100005],cnt[2]; bool bfs(int st) { queue<int>q; vis[st]=1; q.push(st); while(!q.empty()) { int u=q.front(); q.pop(); cnt[vis[u]-1]++; for(int i=0;i<e[u].size();i++) { if(!vis[e[u][i]]) { vis[e[u][i]]=3-vis[u]; q.push(e[u][i]); } else { if(vis[e[u][i]]==vis[u])return 0; } } } return 1; } int main() { int n,m; scanf("%d%d",&n,&m); int a,b; for(int i=1;i<=m;i++) { scanf("%d%d",&a,&b); e[a].push_back(b); e[b].push_back(a); } int maxd=0; for(int i=1;i<=n;i++) { maxd=max(maxd,(int)e[i].size()); } if(maxd==0) { printf("3 %I64d\n",1LL*n*(n-1)*(n-2)/6); } else if(maxd==1) { printf("2 %I64d\n",1LL*m*(n-2)); } else { bool odd=0; ll ans=0; for(int i=1;i<=n;i++) { if(!vis[i]) { cnt[0]=cnt[1]=0; if(!bfs(i)) { odd=1; break; } ans+=1LL*cnt[0]*(cnt[0]-1)/2; ans+=1LL*cnt[1]*(cnt[1]-1)/2; } } if(odd)printf("0 1\n"); else printf("1 %I64d\n",ans); } return 0; }
半回文串指的是对于每一个奇数位置i(1=<i<=(L+1)/2),满足s[i] = s[L-i+1],下标从1開始,给出一个字符串,求字典序第k小的半回文子串。
Trie的应用,挺奇妙的,把每一个回文子串插到Trie中去。cnt[u]记录u这个子树有多少个串。然后在树上查找即可,
不能暴力插子串。能够用一个数组ok[i][j]表示子串s[i...j]是否是半回文串,然后对每一个后缀suffix(x)插入。假设ok[x][i]为true就更新cnt数组,插入完之后须要dfs一遍求子树的siz。查找算法例如以下,假设当前到了节点root,子树1和2的大小分别为w1和w2,那么显然以u为结束节点的子串有w = cnt[root]-w1-w2个,假设w>=k那么算法终止。否则更新k = k - w。假设w1 >= k,那么进入子树1,否则更新k = k-w1,进入子树2。
#include <bits/stdc++.h> #define foreach(it,v) for(__typeof(v.begin()) it = v.begin(); it != v.end(); ++it) using namespace std; const int maxn = 5e3 + 10; typedef long long ll; char s[maxn]; bool ok[maxn][maxn]; int ch[maxn*maxn][2],cnt[maxn*maxn]; struct Trie { int tot; Trie() { cnt[tot = 0] = 0; ch[0][0] = ch[0][1] = -1; } void Insert(const char *s,int st) { int u = 0; for(int i = st; s[i]; i++) { int c = s[i] - 'a'; if(ch[u][c]==-1) { ch[u][c] = ++tot; cnt[tot] = 0; ch[tot][0] = ch[tot][1] = -1; } u = ch[u][c]; if(ok[st][i])++cnt[u]; } } int Init(int u) { if(u==-1) return 0; cnt[u] += Init(ch[u][0]); cnt[u] += Init(ch[u][1]); return cnt[u]; } }; int pre(char * s) { s[0] = ' '; int n = strlen(s); --n; for(int w = 1; w <= n; w++) { for(int x = 1; x + w -1 <= n; x++) { ok[x][x+w-1] = (s[x]==s[x+w-1]); if(w >= 5) ok[x][x+w-1] &= ok[x+2][x+w-3]; } } return n; } void solve(int root,int k) { if(k < 1||root==-1) return; int v1 = ch[root][0],v2 = ch[root][1]; int w1= (v1 == -1 ? 0 : cnt[v1]),w2 = (v2 == -1? 0: cnt[v2]); int w = cnt[root] - w1 - w2; if(w >= k) return; k -= w; if(w1 >= k) { putchar('a'); solve(v1,k); }else { k -= w1; putchar('b'); solve(v2,k); } } int main() { // ios_base::sync_with_stdio(false); // cin.tie(0); int k; while(scanf("%s%d",s+1,&k)==2) { int n = pre(s); Trie A; for(int i = 1; i <= n; i++) A.Insert(s,i); A.Init(0); solve(0,k); putchar('\n'); } return 0; }