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,这个时候看下数据范围q\le10^{18},很显然不行。如果用数位dp的话限制条件又过多,于是pass掉dp的思路。
稍微思考一下公式,nx+my=c,我们令n>m,则一定有n=m*k+t;由于m\le100000,则一定存在t<=100000
这时我们用一个数组f[x]记录满足n*j%m=x里最小的值n*j。因为x的值最大为100000,所以f[x]的值最后总会循环出现。再稍加推导就可以知道:
若一个数c是好的,那么他的倍数c*k也一定是好的。
那么我们让ans+=(q/c)
问题还可以进一步简化。
我们知道一定存在至少一个f_i≠0
这时我们保证好数c中一定有至少0个n
那么我们就让c-f_i,此时即可保证c一定是n的倍数。剩余的量全部分配给m即可。也就是ans+=(q-f[i])/m+1

 

 

#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;
}
暴力(60分)
#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;
}
AC(100分)

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;
}
AC(100分)
#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;
}
标程
posted @ 2019-01-29 23:48  Isaunoya  阅读(339)  评论(0编辑  收藏  举报
TOP