HDU 4972 A simple dynamic programming problem
题意:篮球比赛有1、2、3分球 现给出两队的分差序列(5:3 分差2 3:5分差也是2) 问有多少种可能的比分
思路:
比较简单的想法题 可以类一张表“从分差x到分差y一共有几种情况” 很容易发现只有1->2和2->1的时候会多一种情况 其他均是一种 所以只需要统计这种特殊分差即可 注意一下最后结果要不要乘2 如果最后分差是0就不用因为x:x只有一种 但是最后分差不是0就要乘 因为x:y和y:x算两种 还有本题有坑!! 那个SB记分员会把分数记错 所以一旦记错种类数就为0了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int a[100010];
int main()
{
int t,n,i,l,flag,cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1;i<=n;i++) scanf("%d",&a[i]);
a[0]=0;
l=1;
flag=1;
for(i=1;i<=n;i++)
{
if(abs(a[i]-a[i-1])>3||(a[i]!=1&&a[i]==a[i-1]))
{
flag=0;
break;
}
if(a[i-1]==1&&a[i]==2||a[i-1]==2&&a[i]==1) l++;
}
printf("Case #%d: ",cas++);
if(!flag)
{
printf("0\n");
}
else
{
if(a[n]==0)
printf("%d\n",l);
else printf("%d\n",l*2);
}
}
return 0;
}
HDU 4973 A simple simulation problem
题意:一段区间一开始是1、2、3…n 有m个操作 D操作为区间复制 Q为查询区间最多的相同元素个数
思路:
一看就是线段树… 由于区间会复制 所以自然会想到节点记得是元素个数 比较有意思的是寻找区间方式和以往不同 不过既然已经记录了元素个数 我们就可以按个数来寻找了 我是用(head,num)表示该区间从第head个元素开始操作num个元素 这样就可以实现在线段树上找区间了 注意的是叶子节点特殊处理一下就好
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
#define N 50010
#define L(x) (x<<1)
#define R(x) ((x<<1)|1)
struct node
{
LL sum,max,lazy;
bool leaf;
}f[N*4];
int t,n,m;
void up(int i)
{
f[i].sum=f[L(i)].sum+f[R(i)].sum;
f[i].max=max(f[L(i)].max,f[R(i)].max);
}
void down(int i)
{
if(f[i].lazy!=1)
{
f[L(i)].sum*=f[i].lazy;
f[L(i)].max*=f[i].lazy;
f[L(i)].lazy*=f[i].lazy;
f[R(i)].sum*=f[i].lazy;
f[R(i)].max*=f[i].lazy;
f[R(i)].lazy*=f[i].lazy;
f[i].lazy=1;
}
}
void init(int l,int r,int i)
{
f[i].leaf=false;
f[i].lazy=1;
if(l==r)
{
f[i].leaf=true;
f[i].sum=f[i].max=1;
return ;
}
int mid=(l+r)>>1;
init(l,mid,L(i));
init(mid+1,r,R(i));
up(i);
}
void update(LL head,LL num,int i)
{
if(head==1&&num==f[i].sum)
{
f[i].sum*=2;
f[i].max*=2;
f[i].lazy*=2;
return ;
}
if(f[i].leaf)
{
f[i].sum+=num;
f[i].max+=num;
return ;
}
down(i);
if(f[L(i)].sum>=head+num-1) update(head,num,L(i));
else if(head>f[L(i)].sum) update(head-f[L(i)].sum,num,R(i));
else
{
LL fzc=f[L(i)].sum-head+1;
update(head,fzc,L(i));
update(1,num-fzc,R(i));
}
up(i);
}
LL query(LL head,LL num,int i)
{
if(head==1&&num==f[i].sum) return f[i].max;
if(f[i].leaf) return num;
down(i);
LL res;
if(f[L(i)].sum>=head+num-1) res=query(head,num,L(i));
else if(head>f[L(i)].sum) res=query(head-f[L(i)].sum,num,R(i));
else
{
LL fzc=f[L(i)].sum-head+1;
res=query(head,fzc,L(i));
res=max(res,query(1,num-fzc,R(i)));
}
up(i);
return res;
}
int main()
{
int i,cas=1;
LL l,r;
char op[3];
scanf("%d",&t);
while(t--)
{
printf("Case #%d:\n",cas++);
scanf("%d%d",&n,&m);
init(1,n,1);
while(m--)
{
scanf("%s%I64d%I64d",op,&l,&r);
if(op[0]=='D') update(l,r-l+1,1);
else printf("%I64d\n",query(l,r-l+1,1));
}
}
return 0;
}
HDU 4974 A simple water problem
题意:你可以每次选1个或2个元素使它们+1 问 最少几次操作能从全0加到给出的序列
思路:
一开始一定2个加一次 如果最后只剩下一个就只能1个加一次 所以特判一下最大的元素会不会超过其他元素的和
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef __int64 LL;
LL a,b,c,ans;
int T,t,n;
int main()
{
int i;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
scanf("%d",&n);
a=b=c=0;
for(i=1;i<=n;i++)
{
scanf("%I64d",&a);
c=max(c,a);
b+=a;
}
a=b-c;
if(c>=a) ans=c;
else
{
ans=b/2;
if(ans*2<b) ans++;
}
printf("Case #%d: %I64d\n",t,ans);
}
return 0;
}
HDU 4975 这是个错题… 题意就是HDU 4888
思路:
这题标程的搜索就是错的 错误的方式可以用HDU 4888的数据来hack 说一下怎么解决错题 - -b 要么你和它一样错… 要么就是你网络流跑的快一点 为暴搜留出时间 这样兴许可以搜过去!!
代码:(我写的是和它一样错的… 只要是错的代码 跑的比标程都快… 建议本题别做!!)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1010;
const int MAXM = 1010 * 1010 * 2;
const int INF = 2000000000;
struct Node {
int from, to, next, cap;
} edge[MAXM];
int tol, n;
int head[MAXN], dep[MAXN], gap[MAXN], sumx[MAXN], sumy[MAXN], vis[MAXN];
void addedge(int u, int v, int w) {
edge[tol].from = u;
edge[tol].to = v;
edge[tol].cap = w;
edge[tol].next = head[u];
head[u] = tol++;
edge[tol].from = v;
edge[tol].to = u;
edge[tol].cap = 0;
edge[tol].next = head[v];
head[v] = tol++;
}
int que[MAXN];
void BFS(int start, int end) {
memset(dep, -1, sizeof(dep));
memset(gap, 0, sizeof(gap));
gap[0] = 1;
int front, rear, u, v, i;
front = rear = 0;
dep[end] = 0;
que[rear++] = end;
while (front != rear) {
u = que[front++];
for (i = head[u]; i != -1; i = edge[i].next) {
v = edge[i].to;
if (dep[v] != -1)
continue;
que[rear++] = v;
dep[v] = dep[u] + 1;
++gap[dep[v]];
}
}
}
int cur[MAXN], S[MAXN];
int SAP(int start, int end) {
int i, u, res = 0, top = 0, temp, inser;
BFS(start, end);
memcpy(cur, head, sizeof(head));
u = start;
while (dep[start] < n) {
if (u == end) {
temp = INF;
for (i = 0; i < top; i++)
if (temp > edge[S[i]].cap) {
temp = edge[S[i]].cap;
inser = i;
}
for (i = 0; i < top; i++) {
edge[S[i]].cap -= temp;
edge[S[i] ^ 1].cap += temp;
}
res += temp;
top = inser;
u = edge[S[top]].from;
}
if (u != end && gap[dep[u] - 1] == 0)
break;
for (i = cur[u]; i != -1; i = edge[i].next)
if (edge[i].cap != 0 && dep[u] == dep[edge[i].to] + 1)
break;
if (i != -1) {
cur[u] = i;
S[top++] = i;
u = edge[i].to;
} else {
int min = n;
for (i = head[u]; i != -1; i = edge[i].next) {
if (edge[i].cap == 0)
continue;
if (min > dep[edge[i].to]) {
min = dep[edge[i].to];
cur[u] = i;
}
}
--gap[dep[u]];
dep[u] = min + 1;
++gap[dep[u]];
if (u != start)
u = edge[S[--top]].from;
}
}
return res;
}
bool sol(int u, int fa) {
int i, v;
vis[u] = 1;
for (i = head[u]; ~i; i = edge[i].next) {
v = edge[i].to;
if (!edge[i].cap || v == fa || vis[v] == 2)
continue;
if (vis[v] == 1 || sol(v, u))
return true;
}
vis[u] = 2;
return false;
}
bool findcircle(int fn) {
for (int i = 1; i <= fn; i++) {
vis[i] = 1;
if (sol(i, i))
return true;
vis[i] = 2;
}
return false;
}
int main() {
//freopen("1005.in", "r", stdin);
//freopen("1005.txt", "w", stdout);
int i, j, n1, n2, ans, End, CAS, fff = 1;
scanf("%d", &CAS);
while (CAS--) {
scanf("%d%d", &n1, &n2);
sumx[0] = sumy[0] = 0;
for (i = 1; i <= n1; i++) {
scanf("%d", &sumx[i]);
sumx[0] += sumx[i];
}
for (i = 1; i <= n2; i++) {
scanf("%d", &sumy[i]);
sumy[0] += sumy[i];
}
if (sumx[0] != sumy[0]) {
printf("Case #%d: So naive!\n", fff++);
continue;
}
End = n1 + n2 + 1;
tol = 0;
n = End + 1;
for (i = 0; i < n; i++) {
head[i] = -1;
vis[i] = 0;
}
for (i = 1; i <= n1; i++) {
addedge(0, i, sumx[i]);
for (j = 1; j <= n2; j++)
addedge(i, n1 + j, 9);
}
for (i = 1; i <= n2; i++)
addedge(n1 + i, End, sumy[i]);
ans = SAP(0, End);
if (ans != sumx[0])
printf("Case #%d: So naive!\n", fff++);
else {
if (findcircle(n1))
printf("Case #%d: So young!\n", fff++);
else
printf("Case #%d: So simple!\n", fff++);
}
}
return 0;
}