2019.1.29
60pts + 0 pts+ 15pts = 75pts (我太弱了)
T1
T1【问题描述】 对于给定正整数 n,m,我们称正整数 c 为好的,当且仅当存在非 负整数 x,y,使得 n*x+m*y=c。 现在给出多组数据,对于每组数据,给定 n,m,q,求[1,q]内有 多少个正整数不是好的。 【输入格式】 第一行,一个整数 T 表示数据组数。 接下来每行三个数,分别表示 n,m,q,即一组询问。
【数据范围及约定】 对于 30%的数据,n,m,q≤100。 对于 60%的数据,n,m,q≤10^5。 对于 100%的数据,n≤10^5,m≤10^9,q≤10^18,T≤10。
首先考虑的是dp,这个时候看下数据范围,很显然不行。如果用数位dp的话限制条件又过多,于是pass掉dp的思路。
稍微思考一下公式,,我们令,则一定有;由于,则一定存在。
这时我们用一个数组f[x]记录满足%里最小的值。因为的值最大为100000,所以f[x]的值最后总会循环出现。再稍加推导就可以知道:
若一个数是好的,那么他的倍数也一定是好的。
那么我们让
问题还可以进一步简化。
我们知道一定存在至少一个
这时我们保证好数中一定有至少0个
那么我们就让,此时即可保证一定是的倍数。剩余的量全部分配给即可。也就是;
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll x=0; int f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x*f; } map<ll,bool>mp; signed main(){ #ifndef Open freopen("simple.in","r",stdin),freopen("simple.out","w",stdout); #endif ios::sync_with_stdio(false); int t=read(); for(register int i=1;i<=t;i++){ mp.erase(mp.begin(),mp.end()); int n=read(),m=read(),q=read(); for(register int i=0;i*n<=q;i++) for(register int j=0;i*n+j*m<=q;j++) mp[i*n+j*m]=true; int ans=0; for(register int k=1;k<=q;k++) if(mp[k]) ans++; cout<<q-ans<<endl; } return 0; }
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll x=0; int f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x*f; } const int N=100000+5; int T; ll n,m,q,f[N]; signed main() { #ifndef Open freopen("simple.in","r",stdin),freopen("simple.out","w",stdout); #endif T=read(); while(T--) { n=read(),m=read(),q=read(); if(q<n and q<m) { printf("%lld\n",q); continue; } ll minn=(n<m)?n:m,maxn=n<m?m:n; if(q<maxn and q>=minn) { printf("%lld\n",q-q/minn); continue; } memset(f,-1,sizeof(f)); ll sum=0; f[0]=0; while(1) { sum+=maxn; ll x=sum%minn; if(f[x]!=-1) break; f[x]=sum; } ll ans=0; ans+=(q-f[0])/minn; for(register int i=1; i<minn; i++) if(f[i]!=-1 and q-f[i]>=0) ans+=(q-f[i])/minn+1; printf("%lld\n",q-ans); } return 0; }
T2
T2【问题描述】 给定一棵 n 个节点的树,每条边的长度为 1,同时有一个权值 w。定义一条路径的权值为路径上所有边的权值的最大公约数。现在 对于任意 i∈[1,n],求树上所有长度为 i 的简单路径中权值最大的 是多少。如果不存在长度为 i 的路径,则第 i 行输出 0。 【输入格式】 第一行,一个整数 n,表示树的大小。 接下来 n-1 行,每行三个整数 u,v,w,表示 u,v 间存在一条权值 为 w 的边。 【输出格式】 对于每种长度,输出一行,表示答案。
【数据范围及约定】 对于 30%的数据,n≤1000。 对于额外 30%的数据,w≤100。 对于 100%的数据,n≤4*10^5,1≤u,v≤n,w≤10^6。
树上的操作,
嗯很好,我们要在边上做文章
考虑一下gcd的性质,
我们不需要什么厉害的结论
gcd(a,b)<=min(a,b)
显然吧
考虑边的取值不大,可以枚举一下gcd
假设枚举的gcd是i
那么什么样的路径可以使答案=i
当然是权值>i的边啦
废话。。。光是权值大没有用啊,ta还要有i这个因子啊
换句话说就是权值要是i的倍数
这样我们就可以在枚举gcd的时候,
加入相应的边,找到一条树上的最长路径,更新答案
#include <bits/stdc++.h> using namespace std; typedef long long ll; inline ll read() { ll x=0; int f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x*f; } const int N=400005; struct node { int x,y,nxt; }; node e[N],way[N<<1]; int st[N],sta[1000010],tt=0,tot=0; int p[N<<1],num=0; int ans[N],mxlen,mx,n,link[N<<1]; inline void Add(int u,int w,int z) { tt++,e[tt].x=u,e[tt].y=w,e[tt].nxt=sta[z],sta[z]=tt; } inline void add(int u,int w) { tot++,way[tot].x=u,way[tot].y=w,way[tot].nxt=st[u],st[u]=tot,link[tot]=u; tot++,way[tot].x=w,way[tot].y=u,way[tot].nxt=st[w],st[w]=tot,link[tot]=w; } inline int dfs(int now) { p[now]=num; int mxson=0; for(register int i=st[now]; i; i=way[i].nxt) if(p[way[i].y]!=num) { int r=dfs(way[i].y); mxlen=max(mxlen,r+mxson+1),mxson=max(mxson,r+1); } return mxson; } signed main() { #ifndef Open freopen("walk.in","r",stdin),freopen("walk.out","w",stdout); #endif ios::sync_with_stdio(false); n=read(); for(register int i=1; i<n; i++) { int u=read(),w=read(),z=read(); mx=max(mx,z),Add(u,w,z); } for(register int i=1; i<=mx; i++) { for(register int j=i; j<=mx; j+=i) for(register int k=sta[j]; k; k=e[k].nxt) add(e[k].x,e[k].y); mxlen=0,num++; for(register int k=1; k<=tot; k++) if(p[link[k]]!=num) dfs(link[k]); for(register int k=1; k<=tot; k++) st[link[k]]=0; tot=0,ans[mxlen]=i; } for(register int i=n-1; i>0; i--) ans[i]=max(ans[i],ans[i+1]); for(register int i=1; i<=n; i++) printf("%d\n",ans[i]); return 0; }
#include <stdio.h> #include <iostream> #include <algorithm> #include <memory.h> #include <string.h> #include <vector> #include <time.h> using namespace std; typedef long long LL; typedef pair<int,int> mp; #define pb push_back const int inf = 1<<30; const int maxn = 1000005; const int N = 1000000; int ehead[maxn],ecnt; int head[maxn],cnt; int stk[maxn*2],top; struct edge{ int u,v,next; }rec[maxn],edg[maxn*2]; void add(int u,int v) { edg[++ecnt]=(edge){u,v,ehead[u]}; ehead[u]=ecnt; edg[++ecnt]=(edge){v,u,ehead[v]}; ehead[v]=ecnt; stk[++top]=u;stk[++top]=v; } void _add(int u,int v,int w) { rec[++cnt]=(edge){u,v,head[w]}; head[w]=cnt; } int n,ans[maxn],maxLen; int vis[maxn],idx; int dfs(int u) { int maxc=0;vis[u]=idx; for (int v,j=ehead[u];j;j=edg[j].next) if (vis[v=edg[j].v]!=idx) { int tmpc=dfs(v); maxLen=max(maxLen,maxc+tmpc+1); maxc=max(maxc,tmpc+1); } return maxc; } int main() { #ifndef ONLINE_JUDGE freopen("walk.in","r",stdin); freopen("walk.out","w",stdout); #endif scanf("%d",&n); for (int u,v,w,i=1;i<n;i++) scanf("%d %d %d",&u,&v,&w),_add(u,v,w); for (int i=1;i<=N;i++) { for (int j=i;j<=N;j+=i) for (int k=head[j];k;k=rec[k].next) add(rec[k].u,rec[k].v); maxLen=0;++idx; for (int v,j=1;j<=top;j++) if (vis[v=stk[j]]!=idx) dfs(v); for (int j=1;j<=top;j++) ehead[stk[j]]=0; ecnt=0;top=0;ans[maxLen]=i; } for (int i=n;i>=1;i--) ans[i]=max(ans[i],ans[i+1]); for (int i=1;i<=n;i++) printf("%d\n",ans[i]); return 0; }
T3
T3【问题描述】 给定一个长度为 n 的格子序列 x1,x2,...,xn。每一次 Lyra 可以选 择向左跳到任意一个还没到过的位置,也可以向右跳到任意一个还 没到过的位置。如果现在 Lyra 在格子 i,她下一步跳向格子 j,那 么这次跳跃的花费为|xi-xj|。注意,跳意味着格子 i 和格子 j 中间 其他的格子都不会被这次跳跃影响。并且,Lyra 不应该跳出边界。 Lyra 的初始位置在格子 s。Lyra 将会在到访过所有格子恰好一 次之后,在某个位置停下来,这样就完成了任务。 Lyra 想知道如果她一共向左跳了 L 次,那么她要完成任务的最 小总花费是多少,并希望你输出任意一种花费最小的方案。显然如 果 Lyra 向左走了 L 次,那一定会向右走 n-L-l 次。 特殊的,如果 Lyra 没有办法完成任务,请输出一行-1。 【输入格式】 第一行,三个整数 n, L,s,分别表示序列的大小,向左走的次 数,和初始位置。 第二行,n 个数字,表示序列 xi。
T3咱做不来(咱太弱了)
//minamoto #include<bits/stdc++.h> #define R register #define pi pair<int,int> #define fi first #define se second #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i) #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i) #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v) template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;} using namespace std; char buf[1<<21],*p1=buf,*p2=buf; inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;} int read(){ R int res=1,f=1;R char ch; while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1); for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0'); return res*f; } char sr[1<<21],z[20];int K=-1,Z=0; inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;} void print(R int x){ if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x; while(z[++Z]=x%10+48,x/=10); while(sr[++K]=z[Z],--Z);sr[++K]=' '; } const int N=5e5+5; int x[N],y[N],ans1[N],ans2[N],pos[N],tag[N];pi st[N]; int n,l,s; int solve(int n,int l,int s,int *x,int *ans){ int cnt=0,top=0; if(l<s){ fd(i,s-1,s-l+1)ans[++cnt]=i; fp(i,1,s-l)ans[++cnt]=i; fp(i,s+1,n)ans[++cnt]=i; return x[n]-x[1]+x[s]-x[1]; } l-=s-1; if(l==n-s-1){ fd(i,s-1,1)ans[++cnt]=i; fd(i,n,s+1)ans[++cnt]=i; return ((x[n]-x[1])<<1)-(x[s+1]-x[s]); } fp(i,s+1,n-2)st[++top]=pi(x[i+1]-x[i],i+1); sort(st+1,st+1+top); fp(i,1,top)pos[st[i].se]=i; int sum=0,mn=0,e,j; fp(i,1,l)sum+=st[i].fi; mn=sum<<1,e=n,j=l; for(R int i=n-1,p=l;i>=n-l;--i){ sum-=pos[i]<=p?st[pos[i]].fi:st[p--].fi; while(p&&st[p].se>=i)--p; if(cmin(mn,(sum<<1)+x[n]-x[i]))e=i,j=p; } memset(tag,0,sizeof(tag)); fd(i,s-1,1)ans[++cnt]=i; fp(i,s+2,e-1)if(pos[i]<=j)tag[i]=true; fp(i,s+1,e-1)if(!tag[i+1])ans[++cnt]=i; else{ int tmp=i+1;while(tag[tmp])++tmp; fd(j,tmp-1,i)ans[++cnt]=j; i=tmp-1; } fd(i,n,e)ans[++cnt]=i; return x[n]-x[1]+x[s]-x[1]+mn; } int main(){ // freopen("testdata.in","r",stdin); freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); n=read(),l=read(),s=read(); fp(i,1,n)x[i]=read(),y[n-i+1]=-x[i]; if(l==0&&s!=1||l==n-1&&s!=n)return puts("-1"),0; int c1=solve(n,l,s,x,ans1); int c2=solve(n,n-1-l,n+1-s,y,ans2); if(c1<c2){ print(c1),sr[K]='\n'; fp(i,1,n-1)print(ans1[i]); }else{ print(c2),sr[K]='\n'; fp(i,1,n-1)print(n-ans2[i]+1); } return Ot(),0; }
#include <stdio.h> #include <iostream> #include <algorithm> #include <memory.h> #include <string.h> #include <vector> using namespace std; typedef long long LL; typedef pair<int,int> mp; #define pb push_back const LL inf = 1ll<<50; const int maxn = 200005; int n,l,s,pos[maxn]; int x[maxn],ans1[maxn]; int y[maxn],ans2[maxn]; mp ord[maxn]; bool tag[maxn]; LL solve(int n,int l,int s,int x[],int ans[]) { int cnt=0,tot=0; if (l<s) { for (int i=s-1;i>s-l;i--) ans[++cnt]=i; for (int i=1;i<=s-l;i++) if (i!=s) ans[++cnt]=i; for (int i=s+1;i<=n;i++) ans[++cnt]=i; return (LL)x[n]-x[1]+x[s]-x[1]; } l-=s-1; if (l==n-s-1) { for (int i=s-1;i>=1;i--) ans[++cnt]=i; for (int i=n;i>s;i--) ans[++cnt]=i; return (LL)x[n]-x[1]+x[s]-x[1]+x[n]-x[s+1]; } for (int i=s+1;i<n-1;i++) ord[++tot]=mp(x[i+1]-x[i],i+1); sort(ord+1,ord+tot+1); for (int i=1;i<=tot;i++) pos[ord[i].second]=i; LL minv=inf,sum=0;int e,j; for (int i=1;i<=l;i++) sum+=ord[i].first; minv=sum*2;e=n;j=l; for (int i=n-1,p=l;i>=n-l;i--) { if (pos[i]<=p) sum-=ord[pos[i]].first; else sum-=ord[p--].first; while (p&&ord[p].second>=i) --p; if (sum*2+x[n]-x[i]<minv) { minv=sum*2+x[n]-x[i];e=i;j=p; } } memset(tag,false,sizeof tag); for (int i=s-1;i>=1;i--) ans[++cnt]=i; for (int i=s+2;i<e;i++) if (pos[i]<=j) tag[i]=true; for (int i=s+1;i<e;i++) if (!tag[i+1]) ans[++cnt]=i; else { int tmp=i+1;while (tag[tmp]) ++tmp; for (int j=tmp-1;j>i;j--) ans[++cnt]=j; ans[++cnt]=i;i=tmp-1; } for (int i=n;i>=e;i--) ans[++cnt]=i; return (LL)x[n]-x[1]+x[s]-x[1]+minv; } int main() { #ifndef ONLINE_JUDGE freopen("travel.in","r",stdin); freopen("travel.out","w",stdout); #endif scanf("%d %d %d",&n,&l,&s); for (int i=1;i<=n;i++) scanf("%d",&x[i]); for (int i=1;i<=n;i++) y[i]=-x[n-i+1]; if (s!=1&&l==0) {puts("-1");return 0;} if (s!=n&&l==n-1) {puts("-1");return 0;} LL cost1=solve(n,l,s,x,ans1); LL cost2=solve(n,n-1-l,n-s+1,y,ans2); if (cost1<cost2) { printf("%lld\n",cost1); for (int j=1;j<n;j++) printf("%d ",ans1[j]); } else { printf("%lld\n",cost2); for (int j=1;j<n;j++) printf("%d ",n-ans2[j]+1); } return 0; }