[NOIP模拟测试38]题解
来自达哥的问候……
A.金
显然本题的考察点在于高精而不是裴蜀定理
根据裴蜀定理易得答案为Yes当且仅当$gcd(n,m)=1$,那么考虑怎么在高精度下判互质。
如果$n,m$都能被2整除,那么显然不互质。
如果其中一个可以而另一个不可以(以n能被2整除为例),$gcd(n,m)$就可以转化为$gcd(\frac{n}{2},m)$
如果两个数都不是2的倍数,根据更相减损术得到$gcd(n,m)=gcd(n,|n-m|)$
重复这个过程即可。因为奇数减奇数一定是偶数,所以第三种操作不会连续进行两次,复杂度是log的。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=505;
int T,p[N],q[N];
ll n,m;
ll gcd(ll x,ll y)
{
if(!y)return x;
return gcd(y,x%y);
}
void print(int a[])
{
for(int i=a[0];i;i--)
cout<<a[i];
cout<<endl;
}
void ini(int a[])
{
char s[N];
scanf("%s",s);
a[0]=strlen(s);
for(int i=1;i<=a[0];i++)
a[i]=s[a[0]-i]-'0';
}
ll turnn(int a[])
{
ll res=0;
for(int i=a[0];i;i--)
res=res*10+a[i];
return res;
}
int cmp(int a[],int b[])
{
if(a[0]>b[0])return 1;
if(a[0]<b[0])return 0;
for(int i=a[0];i;i--)
{
if(a[i]>b[i])return 1;
if(a[i]<b[i])return 0;
}
return -1;
}
void jian(int a[],int b[])
{
int fl=cmp(a,b);
if(fl==-1)
{
a[0]=0;
return ;
}
if(fl==1)
{
for(int i=1;i<=a[0];i++)
{
if(a[i]<b[i])
{
a[i+1]--;
a[i]+=10;
}
a[i]-=b[i];
}
while(a[0]>0&&a[a[0]]==0)a[0]--;
return ;
}
} bool is2(int a[])
{
if(a[1]==2||a[1]==0||a[1]==4||a[1]==6||a[1]==8)return 1;
return 0;
}
bool is3(int a[])
{
ll res=0;
for(int i=a[0];i;i--)
res+=a[i];
if(res%3==0)return 1;
return 0;
}
void divi(int a[],int b)
{
int x=0;
for(int i=a[0];i;i--)
{
int old=(x*10+a[i])/b;
x=(x*10+a[i])%b;
a[i]=old;//cout<<a[i]<<endl;
}
while(a[0]>0&&a[a[0]]==0)a[0]--;
return ;
}
bool leg(int a[],int b[])
{
while(a[0]&&b[0])
{
//print(a);print(b);
//cout<<a[0]<<' '<<b[0]<<endl;
if(is2(a)&&is2(b)){return 0;}
if(is2(a))divi(a,2);
else if(is2(b))divi(b,2);
else
{
if(cmp(a,b))jian(a,b);
else jian(b,a);
} }
if(a[0]==a[1]&&a[0]==1)return 1;
if(b[0]==b[1]&&b[0]==1)return 1;
return 0;
}
void qj1()
{ if(m==1)
{
puts("Yes");return ;
}
if(m==0||n==0)
{
puts("No");return ;
}
if(gcd(n,m)==1)
{
puts("Yes");
}
else puts("No");
return ; }
void work()
{
ini(p);ini(q);
if(p[0]<=18&&q[0]<=18)
{
n=turnn(p);m=turnn(q);
qj1();
return ;
}
if(p[0]==1&&p[1]==0)
{
puts("No");
return ;
}
if(q[0]==1&&q[1]==0)
{
puts("No");
return ;
}
if(q[0]==1&&q[1]==1)
{
puts("Yes");
return ;
}
if(q[0]==1&&(q[1]==2||q[1]==3))
{
m=turnn(q);
if(m==2)
{
if(is2(p))puts("No");
else puts("Yes");
}
if(m==3)
{
if(is3(p))puts("No");
else puts("Yes");
}
return ;
}
if(leg(p,q))puts("Yes");
else puts("No");
return ;
}
int main()
{
//while(1)ini(p),divi(p,2),print(p),cout<<p[0]<<endl;
scanf("%d",&T);
while(T--)work();
return 0;
}
B.斯诺
首先考虑序列中只有0和1的情况,这时区间合法当且仅当区间中0的个数等于区间中1的个数。开桶维护,下标为区间中0的个数和1的个数的差值。直接利用前缀和扫一遍即可,复杂度$O(n)$,结合暴力可以得到60分。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e6+5;
int n,a[N],sum[4][N];
ll ans,cnt,bu1[N],bu2[N];
char s[N];
void qj1()
{
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int len=j-i+1,ok=1;
for(int k=0;k<=2;k++)
if((sum[k][j]-sum[k][i-1])*2>len)
{
ok=0;break;
}
if(ok)ans++;
}
cout<<ans<<endl;
}
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'0';
for(int k=0;k<=2;k++)
sum[k][i]=sum[k][i-1]+(a[i]==k);
if(sum[0][i]==sum[1][i])cnt++;
} if(n<=3000)
{
qj1();
return 0;
}
for(int i=1;i<=n;i++)
{
ll m;
if(sum[0][i]>=sum[1][i])
{
ans+=bu1[sum[0][i]-sum[1][i]];
bu1[sum[0][i]-sum[1][i]]++;
if(sum[0][i]==sum[1][i])ans++;
}
else
{
ans+=bu2[sum[1][i]-sum[0][i]];
bu2[sum[1][i]-sum[0][i]]++;
}
}
cout<<ans<<endl;
return 0;
}
那么对于所有情况,显然区间中最多有1个数字数量超过一半,那么合法区间数就是总区间数($\frac{n\times (n+1)}{2}$)减去0超过一半的区间数、1超过一半的区间数和2超过一半的区间数。
对于每种数字维护前缀和,把多一个这种数字看作-1,多一个其它数字看作+1,那么问题转化为求前缀和数组的逆序对个数。可以上树状数组,注意序列要扫到0(因为前缀和的柿子是$sum[r]-sum[l-1]$)。另外,为了防止下标负数要集体加上一个值。复杂度$O(n\ log\ n)$,可以得到90分。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e6+5;
int n,a[N],sum[3][N],c[3][N],minn[3]={0x3f3f3f3f,0x3f3f3f3f,0x3f3f3f3f};
ll ans;
char s[N];
int lb(int x){return x&-x;}
void add(int k,int x,int val)
{
for( ;x<=n;x+=lb(x))
c[k][x]+=val;
}
ll query(int k,int x)
{
ll res=0;
for( ;x;x-=lb(x))
res+=c[k][x];
return res;
}
void show(int k)
{
puts(" ");
for(int i=1;i<=n;i++)
cout<<sum[k][i]<<' ';
puts(" ");
} int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'0';
for(int k=0;k<=2;k++)
sum[k][i]=sum[k][i-1]+(a[i]==k?-1:1),minn[k]=min(minn[k],sum[k][i]);
}
for(int k=0;k<=2;k++)
{
for(int i=0;i<=n;i++)
sum[k][i]+=minn[k]<0?(-minn[k]+1):1;
for(int i=n;i>=0;i--)
ans+=query(k,sum[k][i]-1),add(k,sum[k][i],1);
//cout<<ans<<endl;
//show(k);
}
cout<<1LL*n*(n+1)/2-ans<<endl;
return 0;
}
注意到这个前缀和数组有特殊性:相邻两项的差值最大为1。因此,相邻两项对答案的贡献也最多相差一种值的个数,开桶维护即可。复杂度$O(n)$。
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=5e6+5;
int n,a[N],sum[3][N],bu[3][N],minn[3]={0x3f3f3f3f,0x3f3f3f3f,0x3f3f3f3f};
ll ans;
char s[N];
int main()
{
scanf("%d",&n);
scanf("%s",s+1);
for(int i=1;i<=n;i++)
{
a[i]=s[i]-'0';
for(int k=0;k<=2;k++)
sum[k][i]=sum[k][i-1]+(a[i]==k?-1:1),minn[k]=min(minn[k],sum[k][i]);
}
for(int k=0;k<=2;k++)
{
for(int i=0;i<=n;i++)
sum[k][i]+=minn[k]<0?(-minn[k]+1):1;
ll last=0;
for(int i=n;i>=0;i--)
{
if(i!=n)
{
if(sum[k][i]==sum[k][i+1]+1)ans+=last+bu[k][sum[k][i+1]],last+=bu[k][sum[k][i+1]];
else if(last&&sum[k][i]==sum[k][i+1]-1)ans+=last-bu[k][sum[k][i]],last-=bu[k][sum[k][i]];
else ans+=last;
}
bu[k][sum[k][i]]++;
}
}
cout<<1LL*n*(n+1)/2-ans<<endl;
return 0;
}
C.赤
竟然是wqs二分套wqs二分,$n^3$硬生生砍成$n\ log^2 n$,太残暴了QAQ。
首先暴力dp应该很好想,$dp[i][j][k]$表示遇到了i只猫,丢了j包干脆面和k包豆干。直接三层循环转移即可,边界稍微修剪一下可以得到50分。(然而考场上写着写着莫名其妙丢了一个方程)
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
int n,a,b;
double dp[3][2005][2005],p[100005],q[100005];
void work()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%lf",&p[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&q[i]);
double ans=0;
//dp[1][1][0]=p[1];dp[1][0][1]=q[1];dp[1][1][1]=p[1]+q[1]-p[1]*q[1];
int now=0,pre=1;
for(int i=1;i<=n;i++)
{
now^=1,pre^=1;
for(int j=0;j<=min(i,a);j++)
for(int k=0;k<=min(i,b);k++)
dp[now][j][k]=0;
for(int j=0;j<=min(i,a);j++)
{
for(int k=0;k<=min(i,b);k++)
{
dp[now][j][k]=max(dp[pre][j][k],dp[now][j][k]);//就是它!
if(j>0)dp[now][j][k]=max(dp[pre][j-1][k]+p[i],dp[now][j][k]);
if(k>0)dp[now][j][k]=max(dp[pre][j][k-1]+q[i],dp[now][j][k]);
if(j>0&&k>0)dp[now][j][k]=max(dp[pre][j-1][k-1]+p[i]+q[i]-p[i]*q[i],dp[now][j][k]);
//cout<<i<<' '<<j<<' '<<k<<' '<<dp[now][j][k]<<endl;
}
}
}
for(int i=0;i<=min(n,a);i++)
for(int j=0;j<=min(n,b);j++)
ans=max(ans,dp[now][i][j]);
printf("%.3lf\n",ans);
}
int main()
{
while(scanf("%d%d%d",&n,&a,&b)!=EOF)
work();
return 0;
}
观察这个转移发现是很套路的wqs?不过辣鸡博主根本没写过wqs当然看不出来了。
具体分析就直接放达哥官方题解好了(逃
我们首先不考虑 b 的限制,假设豆干可以任意使用,定义 $f[i][j]$表示前 i 只猫使用 j 包干脆面
和若干包豆干得到的最大收益。直接这么 DP 会 n 只猫都用豆干,可能会超出 b 的限制。
为了减少豆干的使用,我们可以假定使用一个豆干需要额外付出 cost 的代价(也就是在转移
的时候如果一只猫用了豆干,它对期望值的贡献要减去 cost)。在 DP 的时候,求解出 $f[i][j]$的最大值,并记录最优方案中豆干使用的数目 x,那么此时真实的期望是 $f[i][j]$的最优值加上
$x*cost$,这个结果必然也是用了 x 个豆干时能够得到的最优结果。但是,如果我们随便假定一个 cost 去跑 DP,得到的方案并不一定把所有豆干都用完,我们需
要一个能把所有豆干都用完的 cost 的值。显然豆干使用量随着 cost 的变化是单调变化的,我们可以二分 cost 的数值.
这样dp数组就减少了一维,反映在时间复杂度上就是少了个n多了个log。同样地,我们还可以再砍掉一维,然后二分套二分解决。复杂度$O(n\ log^2 \ n)$。
#define hzoj #include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const double eps=1e-9;
int n,a,b,na[100005],nb[100005];
double dp[100005],p[100005],q[100005];
int check(int op,double c1,double c2)
{
for(int i=1;i<=n;i++)
{
dp[i]=dp[i-1];
na[i]=na[i-1];nb[i]=nb[i-1];
if(dp[i-1]+p[i]-c1>dp[i])dp[i]=dp[i-1]+p[i]-c1,na[i]=na[i-1]+1,nb[i]=nb[i-1];
if(dp[i-1]+q[i]-c2>dp[i])dp[i]=dp[i-1]+q[i]-c2,nb[i]=nb[i-1]+1,na[i]=na[i-1];
if(dp[i-1]+p[i]+q[i]-p[i]*q[i]-c1-c2>dp[i])dp[i]=dp[i-1]+p[i]+q[i]-p[i]*q[i]-c1-c2,na[i]=na[i-1]+1,nb[i]=nb[i-1]+1;
}
if(op==1)return nb[n];
else return na[n];
} void work()
{
#ifdef luogu
scanf("%d%d%d",&n,&a,&b);
#endif
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)
scanf("%lf",&p[i]);
for(int i=1;i<=n;i++)
scanf("%lf",&q[i]);
double l1=0.0,r1=1.0,l2,r2,mid1,mid2;
while(r1-l1>eps)
{
mid1=(l1+r1)/2;
l2=0.0,r2=1.0;
while(r2-l2>eps)
{
mid2=(l2+r2)/2;
if(check(1,mid1,mid2)>b)l2=mid2;
else r2=mid2;
}
if(check(2,mid1,r2)>a)l1=mid1;
else r1=mid1;
}
//check(0,r1,r2);
printf("%.3lf\n",dp[n]+1.0*b*r2+1.0*a*r1);
}
int main()
{
#ifdef hzoj
while(scanf("%d%d%d",&n,&a,&b)!=EOF)
#endif
work();
return 0;
}
[NOIP模拟测试38]题解的更多相关文章
- [NOIP模拟测试31]题解
A.math 考场乱搞拿了95,2333. 考虑裴蜀定理:$ax+by=z$存在整数解,当且仅当$gcd(a,b)|z$. 那么如果某个数能够被拼出来,就必须满足所有$a_i$的$gcd$是它的因子. ...
- [NOIP模拟测试30]题解
A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...
- [NOIP模拟测试12]题解
A. 找规律题.儿子的编号减去 小于它编号的最大的fibonacci数 即可得到它父亲的编号. 然后两个节点都暴力上跳就好了.预处理一下fibonacci数,每次二分查找即可. #include< ...
- [NOIP模拟测试11] 题解
A.string 和河北的一道省选题很像.考场上写的暴力桶排,正解其实就是优化一下这个思路. 开线段树维护字符串中每个字母出现的次数.对于每条询问,区间查询.区间赋值维护即可. 另外,本题卡常严重,正 ...
- NOIP模拟测试38「金·斯诺·赤」
金 辗转相减见祖宗 高精 #include<bits/stdc++.h> using namespace std; #define A 2000 #define P 1 #define N ...
- 「题解」NOIP模拟测试题解乱写II(36)
毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组
2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色
2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...
- 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)
2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...
随机推荐
- 【HDOJ6586】String(枚举)
题意:给定一个由小写字母组成的字符串S,要求从中选出一个长度为k的子序列,使得其字典序最小,并且第i个字母在子序列中出现的次数在[l[i],r[i]]之间 n,k<=1e5 思路:大概就是记一下 ...
- ADSL(Asymmetric Digital Subscriber Loop)技术
上行带宽,下行带宽 宽带上行下行是指一般ADSL上网方式上行与下行速率,上行就是从电脑上传的速度,下行就是从网络上的主机下载速度,一般下行速率比较高! ADSL(Asymmetric Digital ...
- 【靶场练习_upload-labs复现】Pass01-020
文件上传本是要命,挂马成功率更是随缘,我太难了Orz Pass-01:JS <?php phpinfo();?> 1.函数重写: 2.禁用js: Pass-02:MIME Type 修改M ...
- 23-25 October in 614
Practice sort 给定一系列形如 \(A<B\) 的不等关系,判断前 \(k\) 个不等关系是否即可确定 \(n\) 个元素之间的大小顺序:如果不可确定,判断前 \(k\) 个不等关系 ...
- python中global的作用域
#python引用变量的顺序: 当前作用域局部变量->外层作用域变量->当前模块中的全局变量->python内置变量 . ''' a=30 声明为全局变量 a=20 为test()函 ...
- Apache: No space left on device: Couldn’t create rewrite_map(XXXX)
启动apache的时候 有时候会遇到这样的错误:No space left on device: Couldn’t create rewrite_map(XXXX) 第一眼看以为是磁盘没有空间了,其实 ...
- 改MYSQL数据库时遇的错
//http://www.dongcoder.com/detail-1103326.html
- English-spoken
May i come in? 我可以进来么? May I introduce myself? 我能做个自我介绍么? I'm sorry I didn't hear that clearly. May ...
- sql查询某个时间内的数据
hour) 七天之前的数据 SELECT * FROM commodity_order where create_time <= (now()-INTERVAL 7 DAY) order by ...
- [MAC]配置Jenkins 开机自启动
如果是将jenkins.war放在tomcat中运行的, 则可以配置开机启动tomcat,脚本如下: XXX表示是你安装Tomcat所在目录 #启动tomcat cd XXX/Tomcat8/bin ...