2019 Multi-University Training Contest 5

1004 equation

一个解很多绝对值的题,这种题记得高中老师讲过,不能依次判断谁大于零,谁小于零,这样的复杂是2的n次方。将每一项的绝对值去掉,假设是大于零,那么公式就是x>b/a,对b/a排序,从左至右判断若当前答案在这个区间内有解,那么进行解方程,判断是否合法。

坑点比较多,排序的时候我是采用分母分子化简式,注意分母要为正,因为当你移项分母的时候大于号小于号会变

求gcd化简得时候,gcd可能会是负的。

当A=0,B==C的时候就是无限解,否则是无解。

输出必须得排序后得输出。。

总结:自己在数学方面得题还是偏弱,前几场数据结构的题听到思路,一个小时左右就可以A了,这个题我写了4个小时才A,主要是样例一直过不了,一直在debug。。。

看了很多人的代码,还是许老师的代码比较容易懂

【代码】

#include
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int N=1e5+10;
int n;
ll c,suma[N],sumb[N];
struct node
{
    ll a,b;
}t[N];
bool cmp(node t1,node t2)
{
    return t1.b*t2.aans,G;
int main()
{
    int _;cin>>_;
    while(_--)
    {
        scanf("%d%lld",&n,&c);
        for(int i=0;i<=n;++i) suma[i]=sumb[i]=0;
        ans.clear();
        G.clear();
        int flag=0;
        for(int i=1;i<=n;++i)
        {
            scanf("%lld%lld",&t[i].a,&t[i].b);
            t[i].b=-t[i].b;
        }
        sort(t+1,t+1+n,cmp);
        for(int i=1;i<=n;++i)
        {
            suma[i]=suma[i-1]+t[i].a;
            sumb[i]=sumb[i-1]-t[i].b;
        }
        for(int i=0;i<=n;++i)
        {
            ll A = suma[i] - (suma[n] - suma[i]);
            ll B = sumb[i] - (sumb[n] - sumb[i]);

            if(!A)
            {
                if(c==B) flag=1;
                continue;
            }
            ll fz=c-B,fm=A;
            ll gc=gcd(fz,fm);
            fz=fz/gc,fm=fm/gc;
            if(fm<0) fm=-fm,fz=-fz;
            int ok=1;
            if(ifm*t[i+1].b)ok=0;
            if(i>0&&fz*t[i].a=0;--i)
            {
                printf(" %lld/%lld",G[i].a,G[i].b);
            }
            puts("");
        }
    }
}

 

1005 permutation 1

给n、k,问用1~n组成排列时,以   p[i+1]-p[i] 为字典序时第k小的字典序时的排列是多少

学习来自qingshanfly。关键在于k不大于10000,那么最多构造长度为8的排列时就可以得到答案了。

另一个重点就是当n>8时,n放在最前面,后面从1开始递增是字典序最小的。n  1 2 3 ...... n-1

【代码】

#include
using namespace std;
const int N=1e5+10;
struct node
{
    int p[30];
    int len;
}a[N];
int b[30];
bool cmp(node a,node b)
{
    for(int i=2;i<=a.len;++i)
    {
        if(a.p[i]-a.p[i-1]!=b.p[i]-b.p[i-1])
        return a.p[i]-a.p[i-1]>_;
    while(_--)
    {
        int n,k;
        scanf("%d%d",&n,&k);
        int pos=0;
        if(n<=8)
        {
            for(int i=1;i<=n;++i) b[i]=i;
            do
            {
                ++pos;
                for(int i=1;i<=n;++i) a[pos].p[i]=b[i];
                a[pos].len=n;
            }while(next_permutation(b+1,b+1+n));
        }
        else
        {
            for(int i=1,j=8;i<=8;++i,--j) b[i]=n-j;
            do{
                ++pos;
                int cnt=0;
                a[pos].p[++cnt]=n;
                for(int i=1;i

1006 string matching

这个题看着跟kmp类似,于是我用普通的kmp疯狂找做法,后来百度一波知道居然是扩展kmp的一道经典例题(最长公共前缀)。

没什么意思,直接贴代码会用板子就行。

#include
#define mt(a) memset(a,0,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll extend[1000001];
ll Next[1000001];
ll min(ll x,ll y)
{
    if(x>y) return y;
    return x;
}
void getNext(char *t,int len)
{
    mt(Next);
    //ll len=t.length();
    Next[0]=len;
    ll a,p;
    a=1;
    while( a 0 ? (p - i + 1) : 0;
            while(i + j < len && t[i+j] == t[j]) j++;
            Next[i]=j;
            a=i;
        }
    }
}
char s[1000100];
int main()
{
    int Case;
    scanf("%d",&Case);
    while(Case--)
    {
        scanf("%s",s);
        int len=strlen(s);
        //exkmp(s,s,len);
        getNext(s,len);
        ll ans=0,num=0;

        for(int i=1;i=len) num++;
            }

        }
        printf("%lld\n",ans+len-1-num);
    }
    ret

1007 permutation 2

给 n x y 问构造长度为n,且1到n各使用一次的方案数是多少?条件:相邻两个数之差的绝对值小于等于2,x

【题解】

当x不为1时,那1位置往右边扩展时必须得往1走去,为了能够回到x+1,唯一得构造方案就是x-2,x-4,接着回来x-3,x-1,x+1.那么这样得方案是唯一的,y也类似。

那么答案就转换为只使用 x+1,到y-1的组成排列的方案数了。那么就是一个dp方程的事了,通过简单观察可以得到递推式

dp[i]=dp[i-1]+dp[i-3](不好解释,很难讲,自己推一遍就知道了)

【代码】

#include
using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll mod=998244353;
ll dp[N];
void init()
{
    dp[1]=1,dp[2]=1;
    for(int i=3;i<=N-5;++i)
        dp[i]=(dp[i-1]+dp[i-3])%mod;
}
int main()
{
    init();
    int _;
    cin>>_;
    while(_--)
    {
        int n,x,y;
        scanf("%d%d%d",&n,&x,&y);
        if(y-x==1)
        {
            if(x==1||y==n) printf("1\n");
            else puts("0");
        }
        else{
            if(x==1&&y==n) printf("%lld\n",dp[n]);
            else if(x==1||y==n) printf("%lld\n",dp[y-x]);
            else printf("%lld\n",dp[y-x-1]);
        }
    }
}

 

你可能感兴趣的:(2019杭电多校题解)