来自达哥的问候……

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]题解的更多相关文章

  1. [NOIP模拟测试31]题解

    A.math 考场乱搞拿了95,2333. 考虑裴蜀定理:$ax+by=z$存在整数解,当且仅当$gcd(a,b)|z$. 那么如果某个数能够被拼出来,就必须满足所有$a_i$的$gcd$是它的因子. ...

  2. [NOIP模拟测试30]题解

    A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...

  3. [NOIP模拟测试12]题解

    A. 找规律题.儿子的编号减去 小于它编号的最大的fibonacci数 即可得到它父亲的编号. 然后两个节点都暴力上跳就好了.预处理一下fibonacci数,每次二分查找即可. #include< ...

  4. [NOIP模拟测试11] 题解

    A.string 和河北的一道省选题很像.考场上写的暴力桶排,正解其实就是优化一下这个思路. 开线段树维护字符串中每个字母出现的次数.对于每条询问,区间查询.区间赋值维护即可. 另外,本题卡常严重,正 ...

  5. NOIP模拟测试38「金·斯诺·赤」

    金 辗转相减见祖宗 高精 #include<bits/stdc++.h> using namespace std; #define A 2000 #define P 1 #define N ...

  6. 「题解」NOIP模拟测试题解乱写II(36)

    毕竟考得太频繁了于是不可能每次考试都写题解.(我解释个什么劲啊又没有人看) 甚至有的题目都没有改掉.跑过来写题解一方面是总结,另一方面也是放松了. NOIP模拟测试36 T1字符 这题我完全懵逼了.就 ...

  7. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  8. 2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色

    2019.8.3 [HZOI]NOIP模拟测试12 B. 数颜色 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 数据结构学傻的做法: 对每种颜色开动态开点线段树直接维 ...

  9. 2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci)

    2019.8.3 [HZOI]NOIP模拟测试12 A. 斐波那契(fibonacci) 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 找规律 找两个节点的lca,需 ...

随机推荐

  1. 十、future其他成员函数、shared_future、atomic(原子操作)

    一. int mythread(){ cout<<"thread"<<endl; std::chrono::milliseconds dura();//5秒 ...

  2. 【HDOJ6582】Path(最短路图,最小割)

    题意: n,m<=1e4,c<=1e9 思路: #include<bits/stdc++.h> using namespace std; typedef long long l ...

  3. opencc模块用langconv替换

    将一下两个py下载并放入代码目录:https://raw.githubusercontent.com/skydark/nstools/master/zhtools/langconv.py https: ...

  4. python之正则表达式(re模块)用法总结

    用一句表示正则表达式,就是 字符串的模糊 匹配

  5. Window随笔 - Windows Server 2012 評估版與延長使用期限【转载】

    Windows Server 2012 評估版與延長使用期限 下載與安裝 至 微軟的評估中心 下載 Windows Server 2012 SP1 180 天軟體試用版 (Windows Server ...

  6. Windows 08R2 IIS网站架设

    目录 目录 配置和安装IIS 环境设置 安装IIS服务器 网站的站点目录和欢迎页面 配置和安装IIS IIS是Windows的网站服务器,所以配置IIS服务的前提是需要一个网址.和DNS域名并添加主机 ...

  7. Windows下使用Composer安装yii2

    Composer简介 Composer 是PHP中用来管理依赖(dependency)关系的工具.你可以在自己的项目中声明所依赖的外部工具库(libraries),Composer会帮你安装这些依赖的 ...

  8. MSF——信息收集(四)

    MSF系列: MSF——基本使用和Exploit模块(一) MSF——Payload模块(二) MSF——Meterpreter(三) MSF——信息收集(四) 发现和端口扫描 Nmap扫描 db_n ...

  9. mysqldump 多实例备份

    通过/var/lib/mysql/mysql4406.sock   登录到某一个实例,备份 mysqldump -uroot -p --all-databases --add-drop-databas ...

  10. POJ 3468 A Simple Problem with Integers(线段树,区间更新,区间求和)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 67511   ...