[CSP-S模拟测试86]题解
好久没有写整套题的题解了呢……主要是这两天考试题愈发神仙 实在是超出了垃圾博主的能力范围啊QAQ
A.异或
不难想到,如果我们得到了$[L,R]$中每一位上0和1的个数,那么答案即为$2 \times \sum \limits _{i=0} ^{\log R} num0[i]\times num1[i] \times 2^i$
所以可以得到一个暴力的思路,枚举$[L,R]$中的每个数按位统计。
现在瓶颈在于区间每一位的0/1个数的统计。如果我们把连续的数写成二进制表示,可以发现一些规律:
000000000000 //0
000000000001 //1
000000000010 //2
000000000011 //3
000000000100 //4
000000000101 //5
000000000110 //6
000000000111 //7
000000001000 //8
000000001001 //...
000000001010
000000001011
000000001100
000000001101
000000001110
000000001111
纵向对比。显然,对于一段连续的整数,它们每一位上的0/1分布是有循环节的,并且循环节内部前一半是0,后一半是1,且循环节长度为$2^{i+1}$。
所以我们可以轻松地求出从0到某个数这段区间里每一位的0/1 个数,相当与一个前缀和,$sum[R]-sum[L-1]$一下就好了。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int T,L,R;
int bit[35][3];
void work()
{
int L=read(),R=read();
for(int i=0;i<31;i++)
{
bit[i][0]=bit[i][1]=0;
int cir=(R+1)/(1<<i+1);
bit[i][0]+=cir*(1<<i);
bit[i][1]+=cir*(1<<i);
int rest=(R+1)%(1<<i+1);
bit[i][0]+=min(rest,1<<i);
bit[i][1]+=max(0,rest-(1<<i));
cir=(L)/(1<<i+1);
bit[i][0]-=cir*(1<<i);
bit[i][1]-=cir*(1<<i);
rest=(L)%(1<<i+1);
bit[i][0]-=min(rest,1<<i);
bit[i][1]-=max(0,rest-(1<<i));
}
ll ans=0;
for(int i=0;i<31;i++)
(ans+=1LL*bit[i][0]*bit[i][1]%mod*(1LL<<i)%mod)%=mod;
printf("%lld\n",ans*2%mod);
} int main()
{
T=read();
while(T--)work();
return 0;
}
B.取石子
首先,最优策略下,先手必败的下一步一定是先手必胜。
可以用类似于筛法(或者说dp也一样)得到所有先手必败的局面,从而得到答案。直接转移是$O(n^4)$的。
不难想到,给定$x,y$之后,使得$(x,y,z)$为先手必败态的$z$只有一个。
然后就可以$O(n^3)$了。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=605,base=300;
bool win[base+5][base+5][base+5];
bool f[4][N][N],g[4][N][N],a[N][N];
int read()
{
int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int T,x,y,z;
bool judge(int i,int j,int k)
{
if(a[j-i+base][k-j+base])return 1;
if(f[0][j][k])return 1;
if(f[1][i][k])return 1;
if(f[2][i][j])return 1;
if(g[0][i][k-j+base])return 1;
if(g[1][j][k-i+base])return 1;
if(g[2][k][j-i+base])return 1;
return 0;
}
void ini()
{
for(int i=0;i<=base;i++)
for(int j=0;j<=base;j++)
for(int k=0;k<=base;k++)
{
if(judge(i,j,k))win[i][j][k]=1;
else
{
a[j-i+base][k-j+base]=1;
f[0][j][k]=f[1][i][k]=f[2][i][j]=1;
g[0][i][k-j+base]=g[1][j][k-i+base]=g[2][k][j-i+base]=1;
}
//cout<<i<<' '<<j<<' '<<k<<' '<<win[i][j][k]<<endl;
}
}
void work()
{
x=read();y=read();z=read();
if(win[x][y][z])puts("Yes");
else puts("No");
}
int main()
{
//freopen("my.out","w",stdout);
ini();
T=read();
while(T--)work();
return 0;
}
C.优化
性质1:绝对值可以直接拆,不会使答案变差。
性质2:除了开头和结尾,中间几段都紧密相连显然最优。
先把绝对值扔了,然后把每个$s_i$单独拿出来,考虑它的贡献。
除了$s_1,s_k$之外,每个$s$产生的系数只能为0或2或-2。
进一步观察还可以发现,两个系数为2的$s$之间,必然存在一段系数为-2的$s$。
系数为0的可以自由穿插在2和-2之间,所以我们可以把阶段划分成4种。最高点(2),最低点(-2),上升段(-2~2),下降段(2~-2)。
那么就可以转移了,看似要$O(n^2 k)$或者$O(n^3 k)$,但考虑到每一段内部每个数的系数都是一样的,所以直接对于每个点判断它在不在这里断段就好了。
$a[]$中可能有负数,所以初始化需要$-inf$。
$O(nk)$。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int N=3e4+5;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}
int n,a[N],K;
int dp[N][202][5];
int main()
{
n=read();K=read();
for(int i=1;i<=n;i++)
a[i]=read();
memset(dp,-0x3f,sizeof(dp));
for(int i=0;i<=n;i++)
for(int j=0;j<4;j++)
dp[i][0][j]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=min(K,i);j++)
{
int p=(j==1||j==K)?1:2;
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j-1][2])+p*a[i];
dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][3])-p*a[i];
dp[i][j][2]=max(dp[i-1][j][2],dp[i][j][1]);
if(j!=1&&j!=K)dp[i][j][2]=max(dp[i][j][2],dp[i-1][j-1][2]);
dp[i][j][3]=max(dp[i-1][j][3],dp[i][j][0]);
if(j!=1&&j!=K)dp[i][j][3]=max(dp[i][j][3],dp[i-1][j-1][3]);
/*cout<<i<<' '<<j<<endl;
for(int k=0;k<4;k++)cout<<dp[i][j][k]<<' ';
puts(" ");*/
}
}
int ans=max(dp[n][K][2],dp[n][K][3]);
printf("%d\n",ans);
return 0;
}
[CSP-S模拟测试86]题解的更多相关文章
- csp-s模拟测试86
csp-s模拟测试86 分屋前的最后一次考试,我早就放弃了自己. 02:02:46 70 02:02:57 03:16:08 100 03:16:08 $T1$忘了按位计算,达哥按位计算的$T1$当时 ...
- CSP-S 模拟测试94题解
T1 yuuustu: 可以对两边取对数,然后就转化为两个double的比较,时间复杂度$O(n)$ 然后我就用神奇0.4骗分水过 #include<bits/stdc++.h> usin ...
- CSP-S模拟测试 88 题解
T1 queue: 考场写出dp柿子后觉得很斜率优化,然后因为理解错了题觉得斜率优化完全不可做,只打了暴力. 实际上他是可以乱序的,所以直接sort,正确性比较显然,贪心可证,然后就是个sb斜率优化d ...
- CSP-S 模拟测试92 题解
话说我怎么觉得我没咕多长时间啊,怎么就又落了20多场题解啊 T1 array: 根据题意不难列出二元一次方程,于是可以用exgcd求解,然而还有一个限制条件就是$abs(x)+abs(y)$最小,这好 ...
- CSP-S 模拟测试57题解
人生第一次A,B层一块考rank2,虽然说分差没几分,但还是值得纪念. 题解: T1 天空龙: 大神题,因为我从不写快读也没有写考场注释的习惯,所以不会做,全hzoi就kx会做,kx真大神级人物. T ...
- CSP-S 模拟测试 51 题解
考试过程: 惯例先看一遍三道题,T1 一开始反应要求割点,但是这是有向图,肯定不能求割点,康了一下数据范围,有40%是树的,还不错,决定待会在打. 看T2 字符串题,完了我字符串最弱了,肯定只能打暴力 ...
- CSP-S 模拟测试 45 题解
由于咕掉的题解太多了,所以只能趁改完不动题的时间,来补补坑qwq,还是太弱了. 考试过程: 到新机房的第一次考试,貌似海星? 第一题一开始就觉得是个贪心,但以为所有小怪兽都要打完,所以想复杂了,但后来 ...
- [CSP-S模拟测试97]题解
A.小盆友的游戏 感觉题解解释的很牵强啊……还是打表找规律比较靠谱 对于每个人,它构造了一个期望函数$f(x)$,设它的跟班个数为$cnt[x]$,那么令$f(x)=2^{cnt[x]}-1$(??鬼 ...
- [CSP-S模拟测试96]题解
以后不能再借没改完题的理由不写题解了…… A.求和 求$\sum \sum i+j-1$ 柿子就不化了吧……这年头pj都不考这么弱智的公式化简了…… 坑点1:模数不定,可能没有2的逆元,那么只要先把乘 ...
随机推荐
- Vagrant 手册之网络 - 端口转发
原文地址 Vagrantfile 配置文件中端口转发的网络标识符:forwarded_port,例如: config.vm.network "forwarded_port", gu ...
- 001---mysql分库分表
mysql分库分表 一.整体的切分方式 1.分库分表:即数据的切分就是通过某种特定的条件,将我们存放在同一个数据库中的数据分散存放到多个数据库(主机)中,以达到分散单台设备负载的效果 2.数据的切分根 ...
- Lambda拉姆达表达式
拉姆达表达式常用于委托,也就是说拉姆达表达式是匿名函数,简单点就是函数. a => a.Equals("string"); //原形为: (a) => { return ...
- Test Case Design Method - OATS
[转载] OATS:即Orthogonal Array Testing Strategy,正交表测试策略. 1 OATS的概念: 次数(Runs):简单的说,就是次数是多少,就有多少个用例. ...
- Java8默认方法
Java8引入的接口默认方法实现一个新的概念.此功能是为了向后兼容性增加,使旧接口可用于利用JAVA8. lambda表达式的能力,例如,列表或集合接口不具备forEach方法声明.从而增加了这样的方 ...
- JavaScript Sort
function ArrayList() { var array = []; this.swap = function(index1, index2) { var aux = array[index1 ...
- Excel 技巧
<!-- Excel跳转到指定行指定列 --> =HYPERLINK("#"&ADDRESS(要跳转到的行数,要跳转到的列数),"跳转")
- Windows下Nginx的启动、停止、重启等命令
Windows下Nginx的启动.停止等命令 在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍. 假设 ...
- webpack2.0 基本使用
webpack是一款前端模块打包工具, 它的出现是由于现代web开发越来越复杂,如果还是像原来那样把所有的js代码都写到一个文件中,维护非常困难.而解决复杂化的方法通常是分而治之,就是把复杂化的东西进 ...
- [POJ3612] Telephone Wire(暴力dp+剪枝)
[POJ3612] Telephone Wire(暴力dp+剪枝) 题面 有N根电线杆,初始高度为h[i],要给相邻的两根连线.可以选择拔高其中一部分电线杆,把一根电线杆拔高\(\Delta H\)的 ...