【长沙集训】2017.9.12

并不怎么傻逼的题也把自己考成傻逼。大概是全机房最后几个改完题的人了。。QAQ

T1 APIO2009抢掠计划

好像是之前哪位学长讲过,tarjan缩点,然后值取反跑spfa或者拓扑排序后做Dp;考场上(第一次)尝试拓扑后DP,然后十分SB地一开始只放进了起点,认为其余入度为0的点无所谓(能过那么多点也是神奇)。实际上显然需要把所有入读为0的点放入栈中,dp值初始为最大,起点为0,然后一边拓扑一边dp;

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
using namespace std;
const int maxn=500000+299;
int s,p,n,m,x,y,a[maxn],is[maxn],fi[maxn],nx[maxn],tt[maxn],ecnt,fir[maxn],nxt[maxn],to[maxn];
int dfs_clock,dfn[maxn],low[maxn],num[maxn],val[maxn],in[maxn],tot,e,f[maxn],ok[maxn];
void add(int x,int y) {
    nx[++ecnt]=fi[x]; fi[x]=ecnt; tt[ecnt]=y;
}
void Add(int x,int y) {
    nxt[++e]=fir[x]; fir[x]=e; to[e]=y; in[y]++;
}
void init(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d%d",&s,&p);
    for(int i=1;i<=p;i++) {
        scanf("%d",&x);
        is[x]=1;
    }
}
stack<int>sta;
void tarjan(int x) {
    dfn[x]=low[x]=++dfs_clock;
    sta.push(x);
    for(int i=fi[x];i;i=nx[i]) {
        if(!dfn[tt[i]]) {
            tarjan(tt[i]);
            low[x]=min(low[x],low[tt[i]]);
        }
        else if(!num[tt[i]]) low[x]=min(low[x],dfn[tt[i]]);
     }
     if(dfn[x]==low[x]) {
         tot++;
         for(;;){
             int u=sta.top();
             sta.pop();
             num[u]=tot;
             val[tot]+=a[u];
             if(is[u]) ok[tot]=1;
             if(u==x) break;
         }
    }
}
stack<int>ss;
void dp() {
    for(int i=1;i<=tot;i++)
        if(!in[i])  ss.push(i);
    memset(f,128,sizeof(f));
    f[num[s]]=val[num[s]];
    while(!ss.empty()) {
        int v=ss.top();
        ss.pop();
        for(int i=fir[v];i;i=nxt[i]) {
            int u=to[i];
            f[u]=max(f[u],f[v]+val[u]);
            in[u]--;
            if(!in[u]) ss.push(u);
        }
    }
}
void work() {
    for(int i=1;i<=n;i++)
    if(!dfn[i]) tarjan(i);
    for(int i=1;i<=n;i++) {
        for(int j=fi[i];j;j=nx[j]) {
            if(num[i]!=num[tt[j]])
                Add(num[i],num[tt[j]]);
         }
    }
    dp();
    int ans=0;
    for(int i=1;i<=tot;i++)
        if(ok[i]) ans=max(ans,f[i]);
    printf("%d\n",ans);
}
int main() {
    freopen("atm.in","r",stdin);
    freopen("atm.out","w",stdout);
    init();
    work();
    return 0;
}

T2 BZOJ 2081 beads

一串字符你可以把它k个化成一份问最多可以得到多少种本质不同的串,正反颠倒相同算同一种。

一看是LLJ大佬曾经讲过的时间为nlogn暴力可过,于是直接哈希,正着哈希一遍反着一遍,暴力跑答案。

一个剪枝,k小于等于n/目前的最大ans,不过好像没太大用。

考场上第一次自己写哈希,然后乱搞了个不知道什么,还写的双哈希,可能也是因为(数)双(据)哈(太)希(弱)让垃圾算法过了一些点

回来抄了一份大佬的代码,才知道哦哈希是这么搞的,不需要求逆元来除(mdzz)而是乘和减,也不需要开数组来存(给自己跪了),最后sort一遍。

大佬的算法比较好的一点是正反存一个结构体,然后据说这样和双哈希效果差不多冲突可能性很小了。

自己的乱搞哈希似乎可以过考试的辣鸡数据,但是不小心一个数组越界了就GG。。。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=2e5+299;
const int N=1e7+5;
const int mod=1e9+7;
LL ti,n,ans,tot,a[maxn],bo[maxn],an[maxn],h[maxn],hf[maxn],base=3;//131;//!!!!!!!
int cnt,tpcnt;
struct node{
    LL z,f;
    friend bool operator <(const node &a,const node&b) {
        return a.z<b.z||(a.z==b.z&&a.f<b.f);
    }
}p[maxn];
LL ksm(int a,int b,int mod) {
    LL res=1,base=a;
    while(b) {
        if(b&1) (res*=base)%=mod;
        (base*=base)%=mod;
        b>>=1;
    }
    return (int)res;
}
void has() {
    h[n]=a[n];
    for(int i=n-1;i>=1;i--)
        h[i]=(a[i]+h[i+1]*base%mod)%mod;
    hf[1]=a[1];
    for(int i=2;i<=n;i++)
        hf[i]=(a[i]+hf[i-1]*base%mod)%mod;
}
void getha(int l,int r,int &z,int &f) {
    z=h[l];
    if(r<n) ((z-=h[r+1]*ksm(base,r-l+1,mod)%mod)+=mod)%=mod;
    f=hf[r];
    if(l>1) ((f-=hf[l-1]*ksm(base,r-l+1,mod)%mod)+=mod)%=mod;
}
int work(int k) {
    int d=n/k,res=0;
    tpcnt=0;
    for(int i=1;i+k-1<=n;i+=k) {
        int tmp1,tmp2;
        getha(i,i+k-1,tmp1,tmp2);
        if(tmp1>tmp2) swap(tmp1,tmp2);
        p[++tpcnt].z =tmp1; p[tpcnt].f=tmp2;
    }
    sort(p+1,p+tpcnt+1);
    for(int i=1;i<=tpcnt;i++) {
        if(p[i].z!=p[i-1].z||p[i].f!=p[i-1].f)
            res++;
    }
    return res;
}
int main() {
    freopen("beads.in","r",stdin);
    freopen("beads.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if(!bo[a[i]]) tot++;
        bo[a[i]]=1;
    }
    if(tot==1) {
    printf("1 ");
    cout<<n<<endl;
    for(int i=1;i<n;i++)
    printf("%d ",i);
    printf("%d\n",n);
    return 0;
    }
    ans=tot; an[cnt=1]=1;
    has();
    for(ti=2;ti<=n/ans;ti++) {
        int now=work(ti);
        if(now>ans) ans=now,an[cnt=1]=ti;
        else if(now==ans) an[++cnt]=ti;
    }
    //printf("%d %d\n",ans,cnt);
    cout<<ans<<" "<<cnt<<endl;
    for(int i=1;i<cnt;i++) printf("%d ",an[i]);
    printf("%d\n",an[cnt]);
    return 0;
}
/*
21
1 1 1 2 2 2 3 3 3 1 2 3 3 1 2 2 1 3 3 2 1
6
1 2 2 1 2 2
*/

T3 Clever

一道水题。随便建边跑spfa,考场上没看到是双向边,而且建向下落的边时开了个结构体存sort了一遍,写法十分毒瘤,也因此后来的spfa和Sort后的点弄混了,就GG。能过这么多点也是不容易。

正解直接暴力问一遍可以连边不就好了啊。。。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const int maxn=100+10;
const int maxm=1e6+299;
int n,f[maxn],fir[maxn],nxt[maxm],to[maxm],ecnt,que[maxn];
double val[maxm],ans=1e9+7,v;
struct node{
    double x,y;
    int id,f;
    friend bool operator <(const node &a,const node&b){
        return a.x<b.x||(a.x==b.x&&a.y<b.y);
    }
}p[maxn];
void add(int u,int v,double w){
    nxt[++ecnt]=fir[u];
    fir[u]=ecnt;
    to[ecnt]=v;
    val[ecnt]=w;
}
double pf(double x) {return x*x;}
double cal(int x,int y){
    return (sqrt(pf(p[x].x-p[y].x)+pf(p[x].y-p[y].y)))/v;
}
double C(int x,int y){
    return sqrt(fabs(p[y].y-p[x].y)*2.0/10.0);
}
double dis[maxn],vis[maxn];
void spfa(){
    queue<int>que;
    for(int i=1;i<=n;i++) dis[i]=1e9+7,vis[i]=0;
    vis[1]=1; dis[1]=0;
    que.push(1);
    while(!que.empty()) {
        int now=que.front();
        que.pop();
        vis[now]=0;
        for(int i=fir[now];i;i=nxt[i]) {
            if(dis[to[i]]>dis[now]+val[i]){
                dis[to[i]]=dis[now]+val[i];
                if(!vis[to[i]]) {
                    vis[to[i]]=1;
                    que.push(to[i]);
                }
            }
        }
    }
    ans=dis[n];
}
int main() {
    freopen("clever.in","r",stdin);
    freopen("clever.out","w",stdout);
    scanf("%d%lf",&n,&v);
    for(int i=1;i<=n;i++) {
        scanf("%lf%lf%d",&p[i].x,&p[i].y,&p[i].f);
        if(i==58) {
            int debug=1;
        }
        add(p[i].f,i,cal(i,p[i].f));
        add(i,p[i].f,cal(i,p[i].f));
    }
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        if(p[i].x==p[j].x) {
            int x,y;double z;
            if(p[i].y>p[j].y) x=i,y=j;
            else x=j,y=i;
            z=C(i,j);
            add(x,y,z);
        }

    spfa();
    printf("%.2lf\n",ans);
    return 0;
}
/*
9 1
5 0 0
5 5 1
6 5 2
7 6 2
6 9 2
3 6 2
4 5 2
3 2 7
7 2 3
*/

T4 逛公园

应该是最有意思的题了。考场上T2自己YY的乱搞hash调了太久没时间写了,就打了输出1还有9分。。。

放一下题

背景

SC theme Park 终于开业了,可爱的平平小朋友很荣幸的成为第一个游客。

公园设计强调,复杂就是美。scp大老板给他的公园设计了一个极其复杂的布局:

由于公园极大,而景点又很多,scp大老板在任意的两个景点之间都建造了一条星光小道,而且还为每条小道制定了方向。

 

题目描述

现在,平平从scp大老板那里得知公园总共有N个景点,并且已经知道了每一条星光小道的方向,但由于平平的方向感极差而RP又极低,于是一旦公园中出现回路,即存在环,平平便会迷路,并且无论怎么走都走不出去。

这样,scp大老板可就伤透脑筋了。为了使平平不会迷路,scp大老板决定改变其中M条星光小道的方向使得公园里不存在回路,但scp大老板又希望改变的小道的条数最少。由于很忙,腾不出时间,scp大老板只好请教即将参加noip的你。(注意:任意两个景点之间有且只有一条星光小道,且任意两条小道都是不相通的,即不能从一条小道不经过景点直接到达另一条小道)。

输入

第一行有一个整数N,表示有N个景点。

接下来是一张N*N的矩阵,第i+1行第j列表示有无从景点i指向景点j的星光小道(0表示没有,1表示有)。

输出

输出仅包括一行,即M的最小值。

输入样例 ( park.in)

4

0 0 0 0

1 0 1 0

1 0 0 1

1 1 0 0

输出样例 ( park.out)

1

数据规模

对于30%数据,1<=N<=10;

对于100%数据,1<=N<=20.

做法还是比较多,题解给的是搜索然而并没有人用搜索做出来?

只有自己看的博客放一下别人的题解好像没什么毛病?

任意两点间都有一条边,而且是有向的,对于这样的有向完全图不存在环当且仅当所有顶点的出度从小到大排列依次为0, 1, 2, ... , n-1,下面我们给出证明:

如果一个有向图的所有点出度都至少为1,那么这个图一定有环,因为在找到环之前DFS总可以找到新的节点。如果有向图无环,必然存在一个点没有出度。由于任两点之间都有有向边,那么其它所有点都要连一条边指向它,这样其它所有点的出度都至少为1了。删掉这个出度为0的点后剩下的图仍然无环,不断对剩下的图继续上面的过程就得到了我们的结论。

我们有了这个结论之后就有很多做法了。

1、搜索,题解说,这样搜索就比较显然了。然后写了个暴力迭代加深,大概只能过30...不知道如何优化

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int n,a[50][50],ans,out[50],ecnt,c[50],tp[50],que[500],vis[50],tot,lim;
int dfs(int cnt,int x,int num,int lim) {
    if(num==n-1&&out[x]==num) return 1;
    if(!x||out[x]==num) {
        for(int i=1;i<=n;i++) {
            if(!vis[i]) {
                vis[i]=1;
                if(dfs(cnt,i,num+1,lim)) return 1;
                vis[i]=0;
            }
        }
        return 0;
    }
    for(int i=1;i<=n;i++) {
        if(a[x][i]&&!vis[i]) {
            int now=abs(out[x]-1-num),tpc=0;
            a[x][i]=0;
            a[i][x]=1;
            out[x]--;
            out[i]++;
            for(int j=0;j<=n;j++) c[j]=0;
            for(int j=1;j<=n;j++) if(!vis[j]) c[out[j]]++;
            for(int j=2;j<=n;j++)
                c[j]+=c[j-1];
            for(int j=1;j<=n;j++) if(!vis[j]) {tp[c[out[j]]--]=j,tpc++;}
            for(int j=1;j<=tpc;j++) {
                now+=abs((num+j)-out[tp[j]]);
            }
            if(cnt+1+now/2<=lim) {
                if(dfs(cnt+1,x,num,lim)) return 1;
            }
            a[x][i]=1;
               a[i][x]=0;
            out[x]++;
            out[i]--;
        }
    }
    return 0;
}
int main() {
    //freopen("park.in","r",stdin);
    //freopen("park.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++) {
            scanf("%d",&a[i][j]);
            if(a[i][j]) {
                out[i]++;
            }
        }
    for(lim=1;lim;lim++) {
        int debug=1;
        if(dfs(0,0,-1,lim))
            break;
    }
    //printf("%d\n",lim);
    cout<<lim;
    return 0;
}

2.模拟退火

LLJ大佬的做法

实在太强啦orz orz

似乎没什么可说的,就跑模拟退火,应该是可以过的。

然后自己之前的板子可能有点问题,非常不稳,换了LLJ大佬的写法之后就可以过了。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<ctime>
using namespace std;
const double T=1e5;
int n,a[50][50],ans,out[50],p[50];
int solve() {
    int res=0;
    random_shuffle(p+1,p+n+1);
    for(int i=1;i<=n;i++) {
        for(int j=i+1;j<=n;j++) {
             if(!a[p[j]][p[i]]) res++;
        }
    }
    double t=T;
    while(t>0.1){
        int x=rand()%n+1,y=rand()%n+1,now=0;
        swap(p[x],p[y]);
        for(int i=1;i<=n;i++) {
        for(int j=i+1;j<=n;j++) {
             if(!a[p[j]][p[i]]) now++;
        }
        }
        if(now<res||rand()<=exp((res-now)/t)*RAND_MAX)
            res=now;
        else swap(p[x],p[y]);
        t*=0.999;
    }
    return res;
}
int main() {
    //freopen("park.in","r",stdin);
    //freopen("park.out","w",stdout);
    srand(time(0));
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        p[i]=i;
        for(int j=1;j<=n;j++) {
            scanf("%d",&a[i][j]);
            if(a[i][j]) {
                out[i]++;
            }
        }
    }
    ans=solve();
    for(int ti=1;ti<=50;ti++) {
        ans=min(ans,solve());
    }
    printf("%d\n",ans);
    return 0;
}

3.状压dp

长沙学长讲的做法,也是SXY大佬的做法。

非常妙啊,十分简洁方便,得出上面的结论后就可以直接跑了,看代码吧。

//Twenty
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
using namespace std;
int n,a[50][50],out[50],dp[1<<20],now,que[50],tot;
int main() {
    freopen("park.in","r",stdin);
    freopen("park.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    int N=(1<<n)-1;
    memset(dp,127,sizeof(dp));
    dp[0]=0;
    for(int i=0;i<N;i++){
        now=0; tot=0;
        for(int j=1;j<=n;j++) {
            if((i&(1<<j-1))) ;
            else que[++tot]=j;
        }
        for(int j=1;j<=tot;j++) {
            now=0;
            for(int k=1;k<=tot;k++)
                if(j!=k&&!a[que[k]][que[j]])
                    now++;
            int x=i|(1<<que[j]-1);
            dp[x]=min(dp[x],dp[i]+now);
        }
    }
    printf("%d\n",dp[N]);
    return 0;
}

总结:

前三题比较简单,但考场上犯了各种各样的错误,其实只是过了样例的程序没爆0就已经超过自己的预料了,码力还是太弱了。

然后t2是本身有点问题,算是学到了新东西。

t4没有时间写比较遗憾,应该是全场最有价值的题吧?当时瞄了一眼有往模拟退火去想,但是没有去找结论,也是没时间,但给时间也不一定能找到,毕竟非常不擅长推结论,只能尽量多见一点题增长下见识吧。

时间: 2024-12-04 21:45:31

【长沙集训】2017.9.12的相关文章

#6030. 【雅礼集训 2017 Day1】矩阵

#6030. 「雅礼集训 2017 Day1」矩阵 题目描述 有一个 n×n  的矩阵,每个位置 (i,j) 如果是 . 表示为白色,如果是 # 表示为黑色. 初始时,每个位置可以是黑色或白色的,(i,j)  位置的值会作为 ai,j 给你. 现在有一种操作,选择两个整数 i,j∈[1,n],记 (i,1),(i,2),…,(i,n) (i, 1), (i, 2)的颜色为 C1,C2,…Cn ??,将 (1,j),(2,j),…,(n,j)  的颜色赋为 C1,C2,…,Cn ??. 你的任务是

2017.11.26【清华集训2017】模拟

T1 5483. [清华集训2017模拟11.26]简单路径T2 5484. [清华集训2017模拟11.26]快乐树T3 5485. [清华集训2017模拟11.26]字符串 T1 结论题,结论很显然任意两条路径权异或后,会将两条路径的交的贡献删去.然后用个桶存一下出现过的异或和,暴力判一下就可以了 code 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<algorithm

[LOJ#2328]「清华集训 2017」避难所

[LOJ#2328]「清华集训 2017」避难所 试题描述 "B君啊,你当年的伙伴都不在北京了,为什么你还在北京呢?" "大概是因为出了一些事故吧,否则这道题就不叫避难所了." "唔,那你之后会去哪呢?" "去一个没有冬天的地方." 对于一个正整数 \(n\),我们定义他在 \(b\) 进制下,各个位上的数的乘积为 \(p = F(n, b)\). 比如 \(F(3338, 10) = 216\). 考虑这样一个问题,已知 \

【第三组】冲刺会议 2017.7.12

冲刺会议 日期:2017.7.12 开发小组:Geomestry 冲刺经理:程立智 成员: 程立智 李明伦 郑昊 蔡镇泽 温志成 汪涵 成员:程立智 完成工作:搭建系统总背景框架,分析之前所做APP与本次APP的通用之处和可移植部分 所遇问题:许多设定还需要商量,现在只能用框框占位 下一步工作:继续开发界面 成员:李明伦 完成工作:学习了部分win2d知识,作为发布经理发布几个界面 所遇问题:对于软件后端实现的细节与需求经理分工暂时不明确 下一步工作:明确分工,继续编写后端 成员:郑昊 完成工作

2017/8/12 考试吐槽

2017 8 12 得分:200 我只能说一句话:这才是$NOIP$难度吧--(神$TM$联赛考$FFT$) A.灌水 题意:$n$根板子长度是$1~n$全排列,找出一种方法,使得板子组成的容器容量恰好为定值. 眼瞪十分钟$+$$coding$ $15$分钟 $+$ $debug$ $5$分钟 $=$ $AC$. 首先我们可以知道,整个容器容量最大的情况就是两根最长的板子夹在两边,中间全是相对较短的板子,这样获得的最大的容量就是\[\frac{(n - 2)(n- 1)}{2 }\].那么我们就

长沙集训day8

长沙集训第8天,此处省略1000000!字.............. t1: 一个进入了"一刀999级"的dalao,要砸钱通关游戏k次,每次打怪都的花费Ai*x+Bi的代价.x为第几次打这个怪物,一共有n的点和m条边,s个终点.而且你打这个怪C次后他就会躲起来,然后你就无法通关.让你就出他能否打过k次通关,如果能就输出最小花费数,否之输出'-1'.然后我就想到用SPFA,别问我为什么不用费用流(因为我还没学QAQ).然后每次跑SPFA,跑完一次记录下到达哪一个终点,然后记录下路径,

2017年12月流行的勒索病毒家族简介by达康勒索病毒解密中心

勒索病毒播报 2017年12月1日-9日 .CHAK .TRUE .GOTHAM .YAYA 爆发范围:重灾区福建 主要攻击对象有数据库的 业务系统 相应软件:金蝶软件 用友软件 通达OA 泛微 OA 病毒特点:文件尾部有4-6个字母 比如   达康勒索病毒解密中心.doc  中毒后 变成  达康勒索病毒解密中心.doc.YAYA 或者  达康勒索病毒解密中心.doc.CHAK 然后留下一个:how to  XXXX html的勒索html html内容是一个id 和两个邮件地址 一个是aol.

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主

[LOJ#2325]「清华集训 2017」小Y和恐怖的奴隶主 试题描述 "A fight? Count me in!" 要打架了,算我一个. "Everyone, get in here!" 所有人,都过来! 小Y是一个喜欢玩游戏的OIer.一天,她正在玩一款游戏,要打一个Boss. 虽然这个Boss有 \(10^{100}\) 点生命值,但它只带了一个随从--一个只有 \(m\) 点生命值的"恐怖的奴隶主". 这个"恐怖的奴隶主&qu

[LOJ#2327]「清华集训 2017」福若格斯

[LOJ#2327]「清华集训 2017」福若格斯 试题描述 小d是4xx9小游戏高手. 有一天,小d发现了一个很经典的小游戏:跳青蛙. 游戏在一个 \(5\) 个格子的棋盘上进行.在游戏的一开始,最左边的两个格子上各有一个向右的青蛙,最右边的两个格子上各有一个向左的青蛙. 每次移动可以选取一个青蛙,向这只青蛙的前方移动一格到空格子中或跳过前方的一个不同朝向的青蛙并移动到空格子中. 为了使你更好地理解这个游戏,我们下发了一个游戏demo作为参考(注意:这个demo中的棋盘大小和题目中并不相同).

[LOJ#2331]「清华集训 2017」某位歌姬的故事

[LOJ#2331]「清华集训 2017」某位歌姬的故事 试题描述 IA是一名会唱歌的女孩子. IOI2018就要来了,IA决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符,第iii个音符的音高为 \(h_i\).IA的音域是 \(A\),她只能唱出 \(1\sim A\) 中的正整数音高.因此 \(1\le h_i\le A\). 在写歌之前,IA需要确定下这首歌的结构,于是她写下了 \(Q\) 条限制,其中第 \(i\) 条为:编号在 \(l_i\) 到 \(r_