猫出的题···果然毒瘤
T1
猫说是送分题,好多人满分,多判了-1挂了10分···
改后代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL long long
using namespace std;
LL A,B,t,ans;
LL gcd(LL a,LL b){
return b==0?a:gcd(b,a%b);
}
void solve(LL a,LL b){
if(ans==-1) return;
if(a==0 || b==0){
return;
}
if(b==1) {
ans+=a; return;
}
if(a>b){
ans+=a/b;
solve(b,a%b);
}
else{
ans+=b/a;
solve(a,b%a);
}
}
int main(){
freopen("dragon.in","r",stdin);
freopen("dragon.out","w",stdout);
scanf("%lld%lld%lld",&A,&B,&t);
if(A==0) return cout<<-1,0;
solve(A,B);
if(ans==-1) puts("-1");
else printf("%lld\n",ans*t);
return 0;
}
T2
模型抽象题?
可以把各种状态之间的关系看成一棵树,树根就是b-a=c-b
从根往子树走就相当于扩展,因为扩展两种一定都可以,而往父亲走就相当于收缩,因为一定只有一种方案
那么就可以看从一开始到最后恰好经过k个点的方案数
因为这是一颗无限满二叉树,所以从每个节点往下其实都是等价的
所以可以先处理出来起点状态和终点状态向上k步的情况
然后dfs往上往下跳再转移就好了
(以及注释是我自己的理解我也看不太懂std写的什么玩意 如果有错请指出)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define maxn 105
#define LL long long
using namespace std;
int n,m,root=-1,str,f[maxn][maxn<<1][maxn<<1],k;
const int mod=1e9+7;
typedef vector<LL> Vec;
Vec c[maxn],d[maxn],now,pre,a,b;
Vec gether(Vec x){
if(x[1]-x[0]==x[2]-x[1]) return x;
Vec ret(3);
if(x[1]-x[0]>x[2]-x[1])
ret[0]=x[0],ret[1]=2*x[1]-x[2],ret[2]=x[1];
else
ret[0]=x[1],ret[1]=2*x[1]-x[0],ret[2]=x[2];
return ret;
}
int dfs(int cur,int p,int q){//还有k步,到最高点还有p步,从lca到b还要q步
if(p<root || cur<0 || q<0) return 0;
int &res=f[cur][p][q];
if(res>=0) return res;
res=0;
if(p>q){
(res+=dfs(cur-1,p-1,q))%=mod;
(res+=dfs(cur-1,p+1,q)*2%mod)%=mod;//往下走,两个子树是等价的
}
if(p==q){//走到了lca
(res+=dfs(cur-1,p-1,q-1))%=mod;
(res+=dfs(cur-1,p+1,min(str-n+m,q+1)))%=mod;
(res+=dfs(cur-1,p+1,q))%=mod;
} return res;
}
int main(){
freopen("rabbit.in","r",stdin);
freopen("rabbit.out","w",stdout);
LL A,B,C,D,E,F;
cin>>A>>B>>C>>D>>E>>F>>k;
a.push_back(A),a.push_back(B),a.push_back(C);
b.push_back(D),b.push_back(E),b.push_back(F);
sort(a.begin(),a.end()); sort(b.begin(),b.end());
c[0]=a; d[0]=b;
for(int i=1;i<=k;i++)
c[i]=gether(c[i-1]),d[i]=gether(d[i-1]);
for(n=0;n<=k;n++){
for(m=0;m<=k;m++)
if(c[n]==d[m]) break;
if(c[n]==d[m]) break;
}
if(n+m>k) return cout<<0,0;//
now=c[n],pre=now;
for(int i=n+1;i<=k;i++){
now=gether(now);
if(now==pre) {
root=i-n-1; break;//lca到根的距离
}
pre=now;
}
if((n+m)%2!=k%2) return cout<<0,0;//
memset(f,0xcf,sizeof f);
str=(k-n-m)/2+n;//从a往上走到的最高处
if(root>=0) root=str-n-root;//从根往下走的最低处
else root=0;
f[0][str-n+m][str-n+m]=1;//初始状态
cout<<dfs(k,str,str-n)<<endl;
return 0;
}
T3
一道暴力能拿92的题qwq但是我暴力好像挂了不少分
正解是分治,因为根据题的性质可以把点分成一排一排的
然后发现l~r中,可以去掉某些点让两部分变成独立的,这就是类似分治的本质qwq
虽然说spfa会死,但是这道题你可以只考虑l~r之中的,所以不会t掉
那个分治写起来还是挺复杂的···
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 50005
#define M 200005
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
int n,m,k,p,q,cnt,head[M];
int bel[M*10],tot;
int sum[M],c[M];
LL dis[M*10],ans[M];
bool vis[M*10];
struct EDGE{
int to,w,nxt;
}edge[M<<1];
struct Query{
int s,t,id;
}ask[M],t[M];
inline void add(int x,int y,int z){
edge[++cnt].to=y; edge[cnt].nxt=head[x];
edge[cnt].w=z; head[x]=cnt;
}
struct data{
int v;
bool operator <(const data &a) const{
return dis[v]>dis[a.v];
}
};
priority_queue <data> Q;
inline void spfa(int l,int r,int s){
for(int i=sum[l-1]+1;i<=sum[r];i++)
dis[i]=1LL<<60;
vis[s]=1,dis[s]=0,Q.push((data){s});
while(!Q.empty()){
int u=Q.top().v; vis[u]=0; Q.pop();
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].to;
if(l>bel[v] || bel[v]>r) continue;
if(dis[v]>dis[u]+edge[i].w){
dis[v]=dis[u]+edge[i].w;
if(!vis[v]) vis[v]=1,Q.push((data){v});
}
}
}
}
void divide(int l,int r,int ql,int qr){
if(ql>qr) return;
if(r-l+1<=k+5){
for(int i=ql;i<=qr;i++){
spfa(l,r,ask[i].s);
ans[ask[i].id]=min(ans[ask[i].id],dis[ask[i].t]);
}return;
}
int ll=r+l-k>>1,rr=ll+k+1;
int qll=ql,q1,q2;
for(int i=ql;i<=qr;i++) t[i]=ask[i];
for(int i=ql;i<=qr;i++)
if(bel[t[i].s]<=ll && bel[t[i].t]<=ll) ask[qll++]=t[i];
q1=qll-1;
for(int i=ql;i<=qr;i++)
if(bel[t[i].s]>=rr && bel[t[i].t]>=rr) ask[qll++]=t[i];
q2=qll-1;
for(int i=ql;i<=qr;i++)
if(!(bel[t[i].s]<=ll&&bel[t[i].t]<=ll || bel[t[i].s]>=rr&&bel[t[i].t]>=rr))
ask[qll++]=t[i];
for(int i=sum[ll]+1;i<=sum[rr-1];i++){
spfa(l,r,i);
for(int j=ql;j<=qr;j++)
ans[ask[j].id]=min(ans[ask[j].id],dis[ask[j].s]+dis[ask[j].t]);
}
divide(l,ll,ql,q1);
divide(rr,r,q1+1,q2);
}
inline int rd(){
int x=0,f=1; char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c>='0' && c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
int main(){
freopen("transport.in","r",stdin);
freopen("transport.out","w",stdout);
n=rd(),m=rd(),k=rd(),p=rd(),q=rd();
for(int i=1;i<=n;i++){
c[i]=rd();
for(int j=1;j<=c[i];j++) bel[++tot]=i;
sum[i]=sum[i-1]+c[i];
}
memset(ans,0x3f,sizeof ans);
for(int i=1;i<=m;i++){
int x=rd(),y=rd(),z=rd();
add(x,y,z); add(y,x,z);
}
for(int i=1;i<=q;i++){
ask[i].s=rd(),ask[i].t=rd(); ask[i].id=i;
}
divide(1,n,1,q);
for(int i=1;i<=q;i++){
if(ans[i]>inf) puts("-1");
else printf("%lld\n",ans[i]);
}
return 0;
}
//5 11 1 2 5
//2 2 2 2 2
//1 2 1
//1 3 2
//2 3 1
//3 4 1
//3 5 2
//4 5 1
//5 6 1
//5 7 2
//6 7 1
//7 8 1
//9 10 1
//1 4
//2 8
//5 7
//9 4
//3 2