【1006】 FangFang (暴力枚举)
8 ffcfffcffcff cffcfff cffcff cffcf ffffcffcfff cffcfffcffffcfffff cff cffc
Case #1: 3 Case #2: 2 Case #3: 2 Case #4: -1 Case #5: 2 Case #6: 4 Case #7: 1 Case #8: -1HintShift the string in the first test case, we will get the string "cffffcfffcff" and it can be split into "cffff", "cfff" and "cff".
题意是找最小的划分 子串在题中已给出 f ff cff cfff cf4 cf5 cf6 cfn 这样只要暴力判两个c之间f的数目即可 如果存在两个c之间f小于2 说明不可划分 否则一定会划分成c的数量个区间 也就是划分的最小数量为c的数量 另外 如果没c 就划分成len/2+len%2 即全划ff或f
额外需要注意的是有空串和其余字符还有串是环串 首尾连在一起的。。。
代码如下:
#include <bits/stdc++.h> using namespace std; char str[1111111]; int pos[1111111]; int tp; int main() { int t,i,z,cnt,f,len; scanf("%d",&t); getchar(); for(z = 1; z <= t; ++z) { gets(str); tp = 0; f = 1; for(i = 0; str[i]; ++i) { if(str[i] == 'c') pos[tp++] = i;//记录每个c的位置 else if(str[i] != 'f') f = 0;//有其余字符 } len = strlen(str); printf("Case #%d: ",z); if(!f) puts("-1");//有其余字符 else if(tp == 0)//没有c { printf("%d\n",len/2+len%2); } else { for(i = 0; i < tp-1; ++i) { if(pos[i+1]-pos[i]-1 < 2)//两个c之间f数量小于2 { f = 0; break; } } if(len-1-pos[tp-1]+pos[0] < 2) f = 0;//特判第一个c和最后一个 因为是成环切割 if(f) { printf("%d\n",tp); }else puts("-1"); } } return 0; }
9 5 6 7 8 113 1205 199312 199401 201314
Case #1: 5 Case #2: 16 Case #3: 88 Case #4: 352 Case #5: 318505405 Case #6: 391786781 Case #7: 133875314 Case #8: 83347132 Case #9: 16520782
首先有这么几个数组
pre //首个c到之后c的距离和
post //最后一个c到之前c的距离和
cnt //点数
ans //答案(任意两个c距离和)
f //最大两个c的间距
1 c
2 ff
3 cff
4 ffcff
5 cffffcff
6 ffcffcffffcff
7 cffffcffffcffcffffcff
这是前几项 很容易推出
cnt[i] = cnt[i-2] + cnt[i-1] //点数
f[i] = f[i-2] + f[i-1] + ((i%2 == 0)? 3: 5) //c 最大间距
然后发现 如果有pre 跟post之后 ans也可推出
ans[i] = post[i-2]*cnt[i-1]+pre[i-1]*cnt[i-2]+x*cnt[i-2]*cnt[i-1]+ans[i-1]+ans[i-2]; // x :两串合并后中间cffffc f数量 跟当前串奇偶有关 x = ((i%2 == 0)? 3: 5)
ans = 前串末c到之前所有c的距离和 * 后串c个数 + 后串首c到之后所有c的距离和*前串c的个数 + 中间f数量*两串c数积 + 两串各自c距离和
原理: 组成新串后 后串任意c到前串每个c的距离等于 前串末c到之前每个c距离+生成新串中间新加f数*前串点数
前串c到后串同理 之后再加上两串各自c距离和即可
这样只需要再推出pre跟post即可
pre[i] = x*cnt[i-1]+pre[i-1]+pre[i-2]+f[i-2]*cnt[i-1] //新串首c到之后c的距离和 继承前后串距离和-pre[i-2,i-1] 然后到后串经过 cnt[i-1]*f[i-2] 和 x*cnt[i-1]
post[i] = x*cnt[i-2]+post[i-1]+post[i-2]+f[i-1]*cnt[i-2] //同上
递推结束 O(1)输出答案即可 注意推到过程中步步取余。。烦= =
代码如下:
#include <bits/stdc++.h> #define mod 530600414 #define ll long long using namespace std; ll f[201316]; ll cnt[201316]; ll ans[201316],pre[201316],post[201316]; int main() { int i,t,n,x; cnt[3] = 1; cnt[4] = 1; f[3] = 0; f[4] = 0; ans[3] = ans[4] = 0; pre[3] = pre[4] = post[3] = post[4] = 0; for(i = 5; i <= 201314; ++i) { cnt[i] = (cnt[i-1]+cnt[i-2])%mod; <span style="white-space:pre"> </span>x = i&1? 5: 3; f[i] = (f[i-1]+f[i-2]+x)%mod; pre[i] = (((x*cnt[i-1]%mod+pre[i-1])%mod+pre[i-2])%mod+f[i-2]*cnt[i-1]%mod)%mod; post[i] = (((x*cnt[i-2]%mod+post[i-1])%mod+post[i-2])%mod+f[i-1]*cnt[i-2]%mod)%mod; ans[i] = (((post[i-2]*cnt[i-1]%mod+pre[i-1]*cnt[i-2]%mod)%mod+x*cnt[i-2]*cnt[i-1]%mod)%mod+ans[i-1]+ans[i-2])%mod; } scanf("%d",&t); for(int z = 1; z <= t; ++z) { scanf("%d",&n); printf("Case #%d: %I64d\n",z,ans[n]); } return 0; }
【1012】 Largest Point (sort)
2 3 2 1 1 2 3 5 -1 0 -3 -3 0 3 3
Case #1: 20 Case #2: 0
两数组排序后直接去第一个判断下标是否一样 一样就比较a取最大*b取次大跟a取次打b最大 输出最大即可
我做的是不断判断。。。
算是个教训 两种都贴上吧
代码如下:
//渣法。。四个判断。。。 #include <bits/stdc++.h> #define ll long long #define mx 2000000 #define fwrite() freopen("../out.out","r",stdout) #define fread() freopen("../in.in","w",stdin) using namespace std; ll a,b; vector <ll> v; ll gt(ll t1,ll t2) { return a*t1*t1+b*t2; } int main() { //fread(); //fwrite(); int n,i,t,sz,z; vector<ll>::iterator it,tmp; ll t1,t2,x,ans; scanf("%d",&t); for(z = 1; z <= t; ++z) { v.clear(); scanf("%d %I64d %I64d",&n,&a,&b); for(i = 0; i < n; ++i) { scanf("%I64d",&x); v.push_back(x); } sort(v.begin(),v.end()); it = lower_bound(v.begin(),v.end(),0); sz = v.size(); if(a < 0 && b < 0)//- - { tmp = it; tmp--; if(it == v.begin() || tmp == v.begin()) { ans = max(gt(v[1],v[0]),gt(v[0],v[1])); } else ans = max(gt(*it,v[0]),gt(*tmp,v[0])); } else if(a < 0 && b >= 0)//- + { tmp = it; tmp++; if(tmp == v.end()) { ans = max(gt(v[sz-1],v[sz-2]),gt(v[sz-2],v[sz-1])); } else if(it == v.begin()) { ans = gt(v[0],v[sz-1]); } else { tmp = it--; ans = max(gt(*it,v[sz-1]),gt(*tmp,v[sz-1])); } } else if(a >= 0 && b <= 0)//+ - { ans = max(gt(v[0],v[1]),gt(v[sz-1],v[0])); } else//+ + { ans = gt(v[0],v[sz-1]); ans = max(ans,gt(v[sz-1],v[sz-2])); ans = max(ans,gt(v[sz-2],v[sz-1])); } printf("Case #%d: %I64d\n",z,ans); } return 0; }
//排序输出。。。慢 慢又怎样 好想啊…………if渣法卡半天TOT #include <bits/stdc++.h> #define ll long long #define mx 2000000 #define fwrite() freopen("../out.out","r",stdout) #define fread() freopen("../in.in","w",stdin) using namespace std; struct Mult { ll ans; int id; bool operator < (const struct Mult a)const { return ans == a.ans? id < a.id : ans > a.ans; } }; Mult mla[6666666],mlb[6666666]; ll a,b; int main() { //fread(); //fwrite(); int n,i,t,z; ll x; scanf("%d",&t); for(z = 1; z <= t; ++z) { scanf("%d %I64d %I64d",&n,&a,&b); for(i = 0; i < n; ++i) { scanf("%I64d",&x); mla[i].ans = a*x*x; mlb[i].ans = b*x; mla[i].id = mlb[i].id = i; } sort(mla,mla+n); sort(mlb,mlb+n); printf("Case #%d: %I64d\n",z,mla[0].id != mlb[0].id? (mla[0].ans+mlb[0].ans): max(mla[0].ans+mlb[1].ans,mla[1].ans+mlb[0].ans)); } return 0; }
【1003】 Minimum Cut (LCA+搜)
1 4 5 1 2 2 3 3 4 1 3 1 4
Case #1: 2
建图方法是先建T树 然后再T树上加m-n+1条边构成G图
在树上每加一条边u,v u跟v的不同子树间都连一条边 也就是u,v一直向上到LCA(u,v)度数++ 这样找最小度数的节点就行 可惜当时渣到不会LCA 有个板子也好……
代码如下:
#include <bits/stdc++.h> using namespace std; #define INF 0x3f3f3f3f const int MAXN = 81000;//点数的最大值 const int MAXM = 604000;//边数的最大值 int rmq[2*MAXN];//rmq数组,就是欧拉序列对应的深度序列 struct ST { int mm[2*MAXN]; int dp[2*MAXN][20];//最小值对应的下标 void init(int n) { mm[0] = -1; for(int i = 1;i <= n;i++) { mm[i] = ((i&(i-1)) == 0)?mm[i-1]+1:mm[i-1]; dp[i][0] = i; } for(int j = 1; j <= mm[n];j++) for(int i = 1; i + (1<<j) - 1 <= n; i++) dp[i][j] = rmq[dp[i][j-1]] < rmq[dp[i+(1<<(j-1))][j-1]]?dp[i][j-1]:dp[i+(1<<(j-1))][j-1]; } int query(int a,int b)//查询[a,b]之间最小值的下标 { if(a > b)swap(a,b); int k = mm[b-a+1]; return rmq[dp[a][k]] <= rmq[dp[b-(1<<k)+1][k]]?dp[a][k]:dp[b-(1<<k)+1][k]; } }; struct Edge { int v,next; }; Edge eg[MAXM]; int head[MAXN],tp; int cnt; int len[MAXN],fa[MAXN]; int P[MAXN];//P[i]表示点i在F中第一次出现的位置 int F[MAXN*2];//欧拉序列,就是dfs遍历的顺序,长度为2*n-1,下标从1开始 ST st; void dfs(int u,int pre,int dep) { fa[u]=pre; F[++cnt] = u; rmq[cnt] = dep; P[u] = cnt; for(int i = head[u];i != -1;i = eg[i].next) { int v = eg[i].v; if(v == pre)continue; dfs(v,u,dep+1); F[++cnt] = u; rmq[cnt] = dep; } } void LCA_init(int root,int node_num)//查询LCA前的初始化 { cnt = 0; dfs(root,root,0); st.init(2*node_num-1); } int query_lca(int u,int v)//查询u,v的lca编号 { return F[st.query(P[u],P[v])]; } void Add(int u,int v) { eg[tp].v = v; eg[tp].next = head[u]; head[u] = tp++; } int dp[MAXN]; void cal(int u,int pre)//搜最小度数 { for(int i = head[u]; ~i; i = eg[i].next) { int v = eg[i].v; if(v == pre) continue; cal(v,u); dp[u] += dp[v]; } } int main() { int t,n,u,v,m,ans; scanf("%d",&t); for(int z = 1; z <= t; ++z) { scanf("%d %d",&n,&m); memset(head,-1,sizeof(head)); tp = 0; for(int i = 0; i < n-1; ++i) { scanf("%d %d",&u,&v); Add(u,v); Add(v,u); } LCA_init(1,n); memset(dp,0,sizeof(dp)); for(int i = n; i <= m; ++i) { scanf("%d %d",&u,&v); dp[u]++; dp[v]++; dp[query_lca(u,v)] -= 2; } cal(1,0); ans = INF; for(int i = 2; i <= n; ++i) ans = min(ans,dp[i]+1); printf("Case #%d: %d\n",z,ans); } return 0; }