noip模拟72[阴间]
noip模拟72 solutions
怎么说我今天觉得这个题特别难??但是别人几乎\(AK\)??
咱也不知道为啥,自己感觉非常难,但是改题确实挺通畅的
所以以后要把所有题都看得简单一些,这样就可以有更多的动力去做题
总是想不到正解??因为见到的题太少了。。。。
T1 出了个大阴间题
这题对我来说确实阴间!!!
至于为什么,我之前见到数据范围不够\(dfs\)的就想状压,然后正解就是\(meet in the middle\)
然后我就充分发挥老祖宗的箴言---吃一堑长一智!!!
这次想都不带想状压,直接\(meet in the middle\)
然后就直接导致我特别想睡觉,就睡过去了,就直接打完暴力就走了。。
按说状压确实挺简单的,这第一维就是选的数的状态,第二维就是当前的\(a\)
但是你发现吧,这个数组我开不出来啊,其实用\(map\)也是可以过得
仔细观察,\(a\)要么是所有选的数的最大值,或者是最大值加一
这样的话最后一维就只剩下两个了,转移就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=25;
const int mod=1e9+7;
int n,k,tag,ans;
struct node{int a,id;}sca[N];
bool cmp1(node x,node y){return x.a==y.a?x.id<y.id:x.a<y.a;}
bool cmp2(node x,node y){return x.id<y.id;}
int f[1<<18][N],g[1<<18][N],mx[1<<18],num[1<<18];
signed main(){
#ifdef oj
freopen("repair.in","r",stdin);
freopen("repair.out","w",stdout);
#endif
scanf("%lld%lld",&n,&k);
fo(i,1,n)scanf("%lld",&sca[i].a);
int U=(1<<n)-1;
fo(s,1,U){
int tot=0,a;
fo(i,1,n){
if((s>>i-1)&1){
mx[s]=max(mx[s],sca[i].a);
tot++;
}
}
num[s]=tot;
if(tot==1)g[s][0]=1;
}
fo(s,1,U){
fo(j,0,1){
if(g[s][j]==0)continue;
fo(i,1,n){
if((s>>i-1)&1)continue;
int now=j+mx[s];
int tmp=now==sca[i].a?now+1:max(now,sca[i].a);
(f[s|(1<<i-1)][tmp-mx[s|(1<<i-1)]]+=(f[s][j]%mod+(k*tmp%mod+(1ll<<num[s]-1)-1)%mod*(g[s][j]%mod))%mod)%=mod;
g[s|(1<<i-1)][tmp-mx[s|(1<<i-1)]]+=g[s][j];
}
}
}
fu(i,1,0)if(g[U][i]){printf("%lld %lld",mx[U]+i,f[U][i]);return 0;}
}
T2 最简单辣快来做
这个我考场上只想到了一半,这个题的处理方式和天使玩偶挺像的
你要拆开绝对值,所以可以将整张图处理四遍,分别对应四种拆绝对值的办法
但是题目很***它的模数不是质数,我不能求逆元,没有拿到满分
我上面思路的实现办法是树状数组,二维的,其实直接求前缀和好像也是可以的
其实在考场上我实现这个东西的时候很没有把握,最后直接硬生生测试点分治给加上了
没想到最后测了一下大样例竟然过了!考场上要相信自己
82pts
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2005;
const int M=2e5+5;
int n,Q,ln,lm,mod,da,db;
struct node{int h,x,y;}sca[N],qus[M];
int lsh[N*2],lh;
void exgcd(int a,int b,int &x,int &y){
if(b==0)return x=1,y=0,void();
exgcd(b,a%b,x,y);
int tmp=x;
x=y;y=tmp-a/b*y;
return ;
}
int inv(int a){
int x,y;
exgcd(a,mod,x,y);
if(x<0)x+=(-x)/mod*mod+mod;
if(x>=mod)x-=x/mod*mod;
return x;
}
int ksm(int x,int y){
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
struct BIT{
int tr[N*2][N*2];
void add(int x,int y,int v){
for(int i=x;i<=lh;i+=(i&(-i)))
for(int j=y;j<=lh;j+=(j&(-j)))
tr[i][j]=(tr[i][j]+v)%mod;
return ;
}
int query(int x,int y){
if(x==0||y==0)return 0;
int ret=0;
for(int i=x;i;i-=(i&(-i)))
for(int j=y;j;j-=(j&(-j)))
ret=(ret+tr[i][j])%mod;
return ret;
}
int ask(int x1,int y1,int x2,int y2){//x1<x2 y1<y2
return (query(x2,y2)+query(x1,y1)+2*mod-query(x1,y2)-query(x2,y1))%mod;
}
}t1,t2,t3,t4;
void spj(){
fo(i,1,n){
scanf("%lld%lld%lld",&sca[i].h,&sca[i].x,&sca[i].y);
lsh[++lh]=sca[i].x;lsh[++lh]=sca[i].y;
}
sort(lsh+1,lsh+lh+1);lh=unique(lsh+1,lsh+lh+1)-lsh-1;
fo(i,1,n){
int x=lower_bound(lsh+1,lsh+lh+1,sca[i].x)-lsh;
int y=lower_bound(lsh+1,lsh+lh+1,sca[i].y)-lsh,h=sca[i].h;
int kx=ksm(da,lsh[x]),ky=ksm(db,lsh[y]);
t1.add(x,y,h*inv(kx)%mod*inv(ky)%mod);
t2.add(x,y,h*inv(kx)%mod*ky%mod);
t3.add(x,y,h*kx%mod*inv(ky)%mod);
t4.add(x,y,h*kx%mod*ky%mod);
}
while(Q--){
int p,q,ans=0;scanf("%lld%lld",&p,&q);
int ip=upper_bound(lsh+1,lsh+lh+1,p)-lsh-1;
int iq=upper_bound(lsh+1,lsh+lh+1,q)-lsh-1;
//cout<<ip<<" "<<iq<<endl;
int kp=ksm(da,p),kq=ksm(db,q);
ans=(ans+t1.ask(0,0,ip,iq)*kp%mod*kq%mod)%mod;//cout<<t1.ask(0,0,ip,iq)<<" "<<ans<<endl;
ans=(ans+t2.ask(0,iq,ip,lh)*kp%mod*inv(kq)%mod)%mod;//cout<<ans<<endl;
ans=(ans+t3.ask(ip,0,lh,iq)*inv(kp)%mod*kq%mod)%mod;//cout<<ans<<endl;
ans=(ans+t4.ask(ip,iq,lh,lh)*inv(kp)%mod*inv(kq)%mod)%mod;//cout<<ans<<endl;
printf("%lld\n",ans);
}
}
signed main(){
#ifdef oj
freopen("satellite.in","r",stdin);
freopen("satellite.out","w",stdout);
#endif
scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&Q,&ln,&lm,&mod,&da,&db);
if(n*Q>500000){spj();return 0;}
fo(i,1,n)scanf("%lld%lld%lld",&sca[i].h,&sca[i].x,&sca[i].y);
while(Q--){
int p,q,ans=0;scanf("%lld%lld",&p,&q);
fo(i,1,n)ans=(ans+sca[i].h*ksm(da,abs(p-sca[i].x))%mod*ksm(db,abs(q-sca[i].y))%mod)%mod;
printf("%lld\n",ans);
}
}
正解就是二维前缀和,离散化之后只剩下\(n^2\)个点,所有纵坐标和横坐标的交点
在离散化数组中查询你询问的坐标,你会发现它不在格点上
我们仍然在四个方向上做二维前缀和,这时候每一次转移都要乘上转移时的系数也就是\(a,b\)
最后我们直接乘上询问点到它所在的格子的四个格点的贡献就好了
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2005;
const int M=2e5+5;
int n,Q,ln,lm,mod,da,db;
struct node{int h,x,y;}sca[N];
int lnsh[N],lnh,lmsh[N],lmh;
int jz[4][N][N],dn[N],dm[N];
int ksm(int x,int y){
if(y<0)return 0;
int ret=1;
while(y){
if(y&1)ret=ret*x%mod;
x=x*x%mod;y>>=1;
}return ret;
}
signed main(){
#ifdef oj
freopen("satellite.in","r",stdin);
freopen("satellite.out","w",stdout);
#endif
scanf("%lld%lld%lld%lld%lld%lld%lld",&n,&Q,&ln,&lm,&mod,&da,&db);
fo(i,1,n){
scanf("%lld%lld%lld",&sca[i].h,&sca[i].x,&sca[i].y);
lnsh[++lnh]=sca[i].x;lmsh[++lmh]=sca[i].y;
}
sort(lnsh+1,lnsh+lnh+1);lnh=unique(lnsh+1,lnsh+lnh+1)-lnsh-1;
sort(lmsh+1,lmsh+lmh+1);lmh=unique(lmsh+1,lmsh+lmh+1)-lmsh-1;
fo(i,1,n){
int x=lower_bound(lnsh+1,lnsh+lnh+1,sca[i].x)-lnsh;
int y=lower_bound(lmsh+1,lmsh+lmh+1,sca[i].y)-lmsh;
jz[0][x][y]=(jz[0][x][y]+sca[i].h)%mod;
jz[1][x][y]=(jz[1][x][y]+sca[i].h)%mod;
jz[2][x][y]=(jz[2][x][y]+sca[i].h)%mod;
jz[3][x][y]=(jz[3][x][y]+sca[i].h)%mod;
}
fo(i,1,lnh)dn[i]=ksm(da,lnsh[i]-lnsh[i-1]);
fo(i,1,lmh)dm[i]=ksm(db,lmsh[i]-lmsh[i-1]);
fo(i,1,lnh)fo(j,1,lmh)jz[0][i][j]=(jz[0][i][j]+jz[0][i-1][j]*dn[i]%mod+jz[0][i][j-1]*dm[j]%mod+mod-jz[0][i-1][j-1]*dn[i]%mod*dm[j]%mod)%mod;
fo(i,1,lnh)fu(j,lmh,1)jz[1][i][j]=(jz[1][i][j]+jz[1][i-1][j]*dn[i]%mod+jz[1][i][j+1]*dm[j+1]%mod+mod-jz[1][i-1][j+1]*dn[i]%mod*dm[j+1]%mod)%mod;
fu(i,lnh,1)fo(j,1,lmh)jz[2][i][j]=(jz[2][i][j]+jz[2][i+1][j]*dn[i+1]%mod+jz[2][i][j-1]*dm[j]%mod+mod-jz[2][i+1][j-1]*dn[i+1]%mod*dm[j]%mod)%mod;
fu(i,lnh,1)fu(j,lmh,1)jz[3][i][j]=(jz[3][i][j]+jz[3][i+1][j]*dn[i+1]%mod+jz[3][i][j+1]*dm[j+1]%mod+mod-jz[3][i+1][j+1]*dn[i+1]%mod*dm[j+1]%mod)%mod;
while(Q--){
int x,y,ans=0;scanf("%lld%lld",&x,&y);
int px=upper_bound(lnsh+1,lnsh+lnh+1,x)-lnsh-1;
int py=upper_bound(lmsh+1,lmsh+lmh+1,y)-lmsh-1;
ans=(ans+jz[0][px][py]*ksm(da,x-lnsh[px])%mod*ksm(db,y-lmsh[py])%mod)%mod;
ans=(ans+jz[1][px][py+1]*ksm(da,x-lnsh[px])%mod*ksm(db,lmsh[py+1]-y)%mod)%mod;
ans=(ans+jz[2][px+1][py]*ksm(da,lnsh[px+1]-x)%mod*ksm(db,y-lmsh[py])%mod)%mod;
ans=(ans+jz[3][px+1][py+1]*ksm(da,lnsh[px+1]-x)%mod*ksm(db,lmsh[py+1]-y)%mod)%mod;
printf("%lld\n",ans);
}
}
T3 是我的你不要抢
对不起,我这个题并不是正解,但是记忆化的\(hash\)使得复杂度有了保障??
最大好像是根号??
不知道不知道,粘上码就溜走
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define ull unsigned long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=6e5+5;
const ull bas=131;
char a[N];
vector<ull> hs[N];
int n,Q,len[N],mx;
int s,t;
ull ba[N];
ull get(int i,int l,int r){return hs[i][r]-hs[i][l-1]*ba[r-l+1];}
map<pair<int,int>,int> mp;
signed main(){
#ifdef oj
freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
#endif
scanf("%d%d",&n,&Q);
fo(i,1,n){
scanf("%s",a+1);
len[i]=strlen(a+1);
mx=max(mx,len[i]);
hs[i].resize(len[i]+5);
fo(j,1,len[i])hs[i][j]=hs[i][j-1]*bas+a[j];
}
ba[0]=1;fo(i,1,mx)ba[i]=ba[i-1]*bas;
while(Q--){
int x,y,ans=0;scanf("%d%d",&x,&y);
if(mp.find(make_pair(x,y))!=mp.end()){
printf("%d\n",mp[make_pair(x,y)]);
continue;
}
fu(i,min(len[x],len[y]),1){
if(get(x,len[x]-i+1,len[x])==get(y,1,i)){ans=i;break;}
}
printf("%d\n",ans);
mp.insert(make_pair(make_pair(x,y),ans));
}
}
T4 显然也是我整的
显然我不会做。。。。。。
怎么说这个题是个找规律的题?
官方题解的构造我没看懂就\(A\)掉了?
无法看懂,只能口胡
首先对于长度小于\(\frac{n}{2}\)的,对于这些求\(GCD\)可以得到他们可以划分出来的块
大于的话,中间会剩下好多啊,删掉就好了,不影响答案
可能会有一些长度加上\(GCD\)之后就大于\(n\)了,这个也可以求\(GCD\)
然后你吧把求过\(GCD\)的都删掉,直接向下递归就行了
为甚可以向下递归,因为你前面所有的可以按照\(GCD\)分组,只需要留下一个然后加上余数就好了
别忘了向下递归之前把刚刚求出来的\(GCD\)放到你的序列里去
AC_code
#include<bits/stdc++.h>
using namespace std;
#define oj
#define int long long
#define fo(i,x,y) for(int i=(x);i<=(y);i++)
#define fu(i,x,y) for(int i=(x);i>=(y);i--)
const int N=2e5+5;
int T,n,m;
set<int> st;
int sta[N],cnt;
int sol(int n){
int ret=0,gcd=0;
if(*st.begin()>n/2){
int B=2*(*st.begin())-n;
ret+=B;n-=B;cnt=0;
for(int i:st)sta[++cnt]=i;
st.clear();fo(i,1,cnt)st.insert(sta[i]-B);
}
while(st.begin()!=st.end()&&*st.begin()<=n/2){
gcd=__gcd(gcd,*st.begin());
st.erase(st.begin());
}
set<int>::iterator it=st.begin();
while(it!=st.end()&&*it+gcd<=n)gcd=__gcd(gcd,*it),it=next(it);
while(st.begin()!=st.end()&&*st.begin()+gcd<=n)st.erase(st.begin());
if(st.begin()==st.end())return ret+gcd;
int newn=gcd+n%gcd;cnt=0;
for(int i:st)sta[++cnt]=i;st.clear();
fo(i,1,cnt)st.insert(sta[i]+newn-n);st.insert(gcd);
return ret+sol(newn);
}
signed main(){
#ifdef oj
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
#endif
scanf("%lld",&T);
while(T--){
scanf("%lld%lld",&n,&m);
fo(i,1,m){
int x;scanf("%lld",&x);
st.insert(x);
}
printf("%lld\n",sol(n));
}
}

浙公网安备 33010602011771号