水题:代码如下
#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;
}