[ARC 066] Tutorial

摘要:
res[n-rk])res[n-rk+=i;elsereturnputs(“0”),0;}inters=1;对于%=MOD;输出函数return0;}问题CD:一个不错的$dp$。由于$sum$和$xor$的对数不能直接计算,请考虑枚举$a,b$,并使用$sum,xorlen$作为限制条件。由于公式:$a+b=aXORb+2*(a&b)$,$a+bleXORb$,只考虑$a+b$的限制,然后问题可以转换为计算每个$sum$的$xor$值的数量,这样$dp[i][s]$可以用于确定前$i$位,$a+b$的总和为$s$。数字,每次$a,B$这一位总共有1次传输(按每一位1的数字传输不会考虑XOR和and的相同情况!

Link:

ARC 066 传送门

C:

如果存在可行方案则答案为$2^{n/2}$

[ARC 066] Tutorial第1张[ARC 066] Tutorial第2张
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+10,MOD=1e9+7;
int n,x,res[MAXN];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        int rk=(n-1+x)/2;
        if(!res[rk+1]) res[rk+1]=i;
        else if(!res[n-rk]) res[n-rk]=i;
        else return puts("0"),0;
    }
    int res=1;
    for(int i=1;i<=n/2;i++) (res*=2)%=MOD;
    printf("%d",res);
    return 0;
}
Problem C

D:

挺不错的一道数位$dp$

由于无法直接计算$sum$和$xor$的对数,因此考虑枚举$a,b$,而将$sum,xorle n$作为限制条件

又因为公式:$a+b=aXORb+2*(a&b)$,所以$a+ble aXORb$,只考虑$a+b$的限制即可

此时问题转化为对于每个$sumle n$求$xor$的取值个数

这样就可以用$dp[i][s]$表示前$i$位确定,$a+b$的和为$s$的个数,每次分$a,b$在该位上总共有几个1转移

(按每位1的个数转移才不会考虑异或与和同时相同的情况!)

但这样复杂度是不对的,在枚举$s$上明显花费了不必要的时间

根据一般数位$dp$记录上限的思想,如果前$i$位的$n-sge 2$,这些数以后都保证合法,就能统一计算了

这样就从$dp[i][s]$变成了$dp[i][0/1/2]$

[ARC 066] Tutorial第3张[ARC 066] Tutorial第4张
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
#define MAX_D 64
#define MOD ((ll)1e9 + 7)
ll N,dp[MAX_D][3],res;int nxt;

int main() 
{    
    scanf("%lld",&N);
    dp[MAX_D-1][0]=1;
    for(int i=MAX_D-1;i>0;i--) 
        for(int j=0; j <= 2; j++)
            for(int k=0;k<=2;k++) 
            {
                nxt=j*2+((N>>(i-1))&1)-k;
                if (nxt<0) continue;
                nxt=nxt>2?2:nxt;
                (dp[i-1][nxt]+=dp[i][j])%=MOD;
            }
    res=0;
    for (int i=0;i<=2;i++) (res+=dp[0][i])%=MOD;
    printf("%lld
", res);
    return 0;
}
Solution A

从后往前用记忆化搜索的形式写起来更加方便

一开始将上限值就设为$n$,每次确定最后一位取几个以后去掉最后一位,不用考虑和的合法性了

[ARC 066] Tutorial第5张[ARC 066] Tutorial第6张
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
const int MOD=1e9+7;
map<ll,ll> dp;ll n;

ll dfs(ll x)
{
    if(dp.count(x)) return dp[x];
    return dp[x]=(dfs(x>>1)+dfs((x-1)>>1)+dfs((x-2)>>1))%MOD;
}

int main()
{
    scanf("%lld",&n);
    dp[0]=1;dp[1]=2;
    printf("%lld",dfs(n));
    return 0;
}
Solution B

E:

首先要观察出几点性质:

1、只有在减号后可能加括号

2、括号不可能嵌套超过两层,否则可以转化为只有两层的简化情况

这样就可以记录$dp[0/1/2]$分别表示当前还有几个左括号未匹配的最大值来$dp$了

[ARC 066] Tutorial第7张[ARC 066] Tutorial第8张
#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
int n,x;char op;ll dp[3],nxt[3];

int main()
{
    scanf("%d%d",&n,&dp[0]);
    dp[1]=dp[2]=-1ll<<60;
    for(int i=1;i<n;i++)
    {
        scanf(" %c%d",&op,&x);
        if(op=='-') x=-x;
        nxt[0]=dp[0]+x,nxt[1]=dp[1]-x,nxt[2]=dp[2]+x;
        dp[0]=max(nxt[0],max(nxt[1],nxt[2]));
        if(op=='+') dp[1]=max(nxt[1],nxt[2]),dp[2]=nxt[2];
        else dp[1]=dp[0],dp[2]=max(nxt[1],nxt[2]);
    }
    printf("%lld",dp[0]);
    return 0;
}
Solution A

其实也可以不用$dp$,考虑如果在某个减号后加了第一个括号的最优解

发现此时能保证将下一个减号后的值都变为正贡献,但对当前位到下一个减号间的值是无能为力的

这样枚举第一个括号的位置对答案更新即可

[ARC 066] Tutorial第9张[ARC 066] Tutorial第10张
#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
typedef long long ll;
typedef pair<int,int> P;
const int MAXN=1e5+10;
char op[MAXN];
int n,dat[MAXN],nxt[MAXN],fst;
ll suf[MAXN],cur,res=-1ll<<60;

int main()
{
    scanf("%d%d",&n,&fst);
    for(int i=1;i<n;i++)
        scanf(" %c%d",&op[i],&dat[i]);
    cur=n;
    for(int i=n-1;i;i--)
    {
        suf[i]=suf[i+1]+dat[i];
        if(op[i]=='-') nxt[i]=cur,cur=i;
    }
    cur=0;
    for(int i=1;i<n;i++)
        if(op[i]=='-') 
            res=max(res,cur-suf[i]+2*suf[nxt[i]]),cur-=dat[i];
        else cur+=dat[i];
    res=max(res,cur);
    printf("%lld",res+fst);
    return 0;
}
Solution B

F:

免责声明:文章转载自《[ARC 066] Tutorial》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[Codeforces #210] Tutorial[网络流24题] 魔术球问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

2010年11月编程语言排行榜

Tiobe今天发布了最新一期的编程语言排行榜。本期榜单的前五名与10月份没有明显变化,依然是Java、C、C++、PHP和Python;Objective-C的增长势头强劲。本期另外一个值得注意的语言是重回前20名NXT-G。NXT-G是一种集成在乐高(LEGO)公司的机器人玩具产品中的可视化编程语言,关于NXT-G的详细报道可以参考2008年11月的编程语...

Prim算法和Dijkstra算法的异同

之前一直觉得Prim和Dijkstra很相似,但是没有仔细对比; 今天看了下,主要有以下几点: 1: Prim是计算最小生成树的算法,比如为N个村庄修路,怎么修花销最少。 Dijkstra是计算最短路径的算法,比如从a村庄走到其他任意村庄的距离。 2: Prim算法中有一个统计总len的变量,每次都要把到下一点的距离加到len中; Dijkstra算法中却没...

最大流模板

AC HDU 3061 一道最大权闭合子图裸题 以前写的DINIC太慢了啊TAT 老T..... 这个DINIC加了俩优化....... 当前弧优化.在一次增广中,我们总是从某个节点一条弧一条弧地放流,也就是说我们依次把弧塞满....    把某条弧塞满以后接下来的DFS过程中就不需要再遍历这条弧了.......    那我可以通过修改边表避免以后再遍历...

【BZOJ3489】A simple rmq problem(K-D Tree)

题目说了要在[l,r]中找只出现过一次的数,那么就可以转换成是说上一次这个数出现在l之前,下一次这个数出现在r之后,且最大,那么就可以转化成一个K-D Tree问题。 设(pre[i])为上一次(a[i])出现的位置,(nxt[i])为下一次(a[i])出现的位置,那一个结构体({i,pre[i],nxt[i]}),建三维K-D Tree,在K-D Tree...

Codeforces Round #127 (Div. 1) D. Brand New Problem 暴力dp

D. Brand New Problem 题目连接: http://www.codeforces.com/contest/201/problem/D Description A widely known among some people Belarusian sport programmer Lesha decided to make some money...

HDU 2457 DNA repair AC自动机+dp

调了1天,居然是我的AC自动机板子有问题。。。 这个板子是真的繁琐 8/27/21:16 已更新简洁版本 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #includ...