组队模拟
目录
概况
本次模拟采用组队形式,题目难度橙-蓝-蓝
A.cubicp
思路
首先觉得有点难,后来仔细看看,dlm又推了推式子,再读个题,半小时顺利切掉,具体推导如下:
一个 P 数如果是立方差数,不妨假设是 x3-y3(x>y)。相当于(x-y)(x2+xy+y2),由于 P 是质数,因此 x=y+1。又有(x-1)2+x2+x(x-1)=P,暴力枚举 1~10^6 判断即可。
代码
#include <bits/stdc++.h>
using namespace std;
long long n;
bool flag=1;
long long js(long long x){
return 3*x*x+3*x+1;
}
int main(){
freopen("cubicp.in","r",stdin);
freopen("cubicp.out","w",stdout);
long long q,p;
scanf("%lld",&q);
for(int i=1;i<=q;i++){
flag=1;
scanf("%lld",&p);
for(int j=1;j<=600000;j++){
if(js(j)==p){
printf("YES\n");
flag=0;
break;
}
}
if(flag==1)printf("NO\n");
}
return 0;
}
歧途
开始的时候没有抓住质数这个点,只是去想公式怎么推,但后来发现质数才是解题关键,要小心思维陷阱
B.dp
思路
本题第一眼以为是线段树,但是显然没有具体维护的值,所以推测应该是区间dp,dp[i][j]表示前i个数分为j段时的价值,枚举这个断点k,有dp[i][j]=min{dp[k][j-1]+sum(k+1,i)},但是这个算法显然时间是假的,观察一下式子符合决策单调性的条件,所以需要决策单调性优化
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100010;
int c[N],a[N];
ll f[N],g[N];
int p,q,n,k;
ll tot;
void move(int l,int r)
{
while (l<p) p--,tot+=c[a[p]],c[a[p]]++;
while (r>q) q++,tot+=c[a[q]],c[a[q]]++;
while (p<l) c[a[p]]--,tot-=c[a[p]],p++;
while (r<q) c[a[q]]--,tot-=c[a[q]],q--;
}
void work(int l,int r,int fl,int fr)
{
if (fl>fr) return;
int mid=(fl+fr)>>1,mi;
ll mx=1LL<<60;
for (int i=l;i<=r;i++)
if (i<mid)
{
move(i+1,mid);
if (f[i]+tot<mx) mx=f[i]+tot,mi=i;
}
g[mid]=mx;
work(l,mi,fl,mid-1);
work(mi,r,mid+1,fr);
}
int main()
{
//freopen("dp.in","r",stdin);
//freopen("dp.out","w",stdout);
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
f[0]=0;
for (int i=1;i<=n;i++) f[i]=1LL<<60;
while (k--)
{
p=1,q=0,tot=0;
for (int i=1;i<=n;i++) c[i]=0;
work(0,n-1,1,n);
for (int i=0;i<=n;i++) f[i]=g[i],g[i]=0;
}
printf("%lld",f[n]);
return 0;
}
历程
在写暴力dp的路上没什么波澜但是一去不复返,60分还比较好拿,但是在优化时发现自己决策单调性优化学了个寂寞,于是遗憾卡40,最后还得跟学长乖乖学。但是没太学会,还得再看(
注:move部分因为借鉴了一点莫队的思路,所以时间复杂度容易算错,不会出现根号,而是纯的O(nlogn)
C.number
思路
对于每两个区间,求区间交与区间并,显然,若两个区间值相同,则交不能为空,若两个区间值不同,则当值较大时,不能在添加一个值较小的区间,即排序后查询区间交,合法情况下使区间并删除,采用线段树或并查集维护
代码
#include<bits/stdc++.h>
#define mod 1000000007
#define ll long long
#define N 1000100
#define mid (l+r>>1)
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){
if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){
x=x*10+c-'0';c=getchar();}
return x*f;
}
struct yjx{
int l,r,x;}a[N],t[N];
int fa[2*N],n,T;
bool cmp(yjx x,yjx y){
return x.x>y.x;}
int find(int x){
return fa[x]==x?x:fa[x]=find(fa[x]);}
bool check(int x){
for(int i=1;i<=n*2;i++)fa[i]=i;
for(int i=1;i<=x;i++)t[i]=a[i];
sort(t+1,t+x+1,cmp);
int lmin,lmax,rmin,rmax;
lmin=lmax=t[1].l;
rmin=rmax=t[1].r;
for(int i=1;i<=x;i++){
if(t[i].x<t[i-1].x){
if(find(lmax)>rmin)return 1;
for(int j=find(lmin);j<=rmax;j++)fa[find(j)]=find(rmax+1);
lmin=lmax=t[i].l;
rmin=rmax=t[i].r;
} else{
lmin=min(lmin,t[i].l);
lmax=max(lmax,t[i].l);
rmin=min(rmin,t[i].r);
rmax=max(rmax,t[i].r);
if(lmax>rmin)return 1;
}
}
if(find(lmax)>rmin)return 1;
return 0;
}
int main(){
n=read(),T=read();int l=1,r=n;
for(int i=1;i<=T;i++)a[i].l=read(),a[i].r=read(),a[i].x=read();
while(l<r){
if(check(mid))r=mid;else l=mid+1;}
printf("%d",l);
return 0;
从塞罕坝到ybt黑洞
在做题的途中,隔壁巨神提出了一种塞罕坝做法:种一千棵线段树!我仔细思索了一下, 发现这种做法显然可以用枚举曾经出现过的操作特判解决,可以轻松得到八十分,时间复杂度O(n2),但是明知道正解会带log可是不知道怎么解决,于是……在考试结束后,学长公布了正确的答案,二分加并查集,没错ybt黑洞并查集,而且思路很清奇,使相邻的节点成为并查集
D.edit
思路
我们不需要考虑修改内容是什么,只需要考虑进行哪一步操作,显然如果一样,可以直接从上一位转移,若不一样,则可以插入、删除或修改,易得状态转移方程:
if(s1[i]==s2[j])dp[i][j]=dp[i-1][j-1];
else dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
代码
#include<bits/stdc++.h>
#define N 2007
#define ll long long
using namespace std;
int dp[N][N],len1,len2,len;
char s1[N],s2[N];
int main(){
char c=getchar();while(c!='\n'){
s1[++len1]=c;c=getchar();}
c=getchar();while(c!='\n'){
s2[++len2]=c;c=getchar();}
memset(dp,0x3f,sizeof(dp));dp[0][0]=0;
for(int i=1;i<=len1;i++)dp[i][0]=i;
for(int i=1;i<=len2;i++)dp[0][i]=i;
for(int i=1;i<=len1;i++)
for(int j=1;j<=len2;j++){
if(s1[i]==s2[j])dp[i][j]=dp[i-1][j-1];
else dp[i][j]=min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1]))+1;
}
printf("%d",dp[len1][len2]);
return 0;
}
“我样例出错啦!!!”
最开始看这道题确实有一点恍惚,进入了作者设下的思维陷阱,开始考虑修改之后的内容,本来想通过最长公共子序列解决,但很快被我自己hack掉了(这是个伏笔),然后老师公布答案,才发现根本不需要考虑修改内容,于是快速写完了代码。但是!我自己造的数据和我手动模拟答案不一样!!!找各路大佬debug,最后冒险交了一下,过了?!!!!!,最后在周围人的帮助下,才发现,数据,出错了……样例不谨慎,程序两行泪呜呜呜