NOIP 模拟测试
1 任务安排
manage.in/.out/.cpp
1.1 问题描述
你有 N 个工作,同一时刻只能做一个任务, 其中每个工作有其所需时
间, 及完成的 Deadline(截止时间), 问要完成所有工作, 最迟要从什么时候开
始。
你最早可以从时间 0 开始工作。
1.2 输入格式
第一行一个整数 N,表示任务数量
接下来 n 行,每行两个整数,T i ,S i ,分别表示该任务的持续时间和截
止时间。
1.3 输出格式
输出一个整数,表示最晚的开始时间,如果不能完成,输出-1。
1.4 样例输入
4
3 5
8 14
5 20
1 16
1.5 样例输出
2
1.6 数据规模及约定
对于 40% 的数据,N <= 20
对于 60% 的数据,N <= 1000
对于 100% 的数据,1<= N <= 100000
1<= T i <= 100000
1<= S i <= 1000000
/* 贪心遇到不合法的统计答案 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 100007 using namespace std; int n,ans,tot; struct node { int Ti,Si; bool operator < (const node &x)const{ return Si<x.Si; } }a[N]; inline int read() { int x=0,f=1;char c=getchar(); while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } int main() { freopen("manage.in","r",stdin); freopen("manage.out","w",stdout); int x,y; n=read(); for(int i=1;i<=n;i++) { x=read();y=read(); a[i].Ti=x;a[i].Si=y; } sort(a+1,a+n+1); tot=0;int flag=0;ans=0x3f3f3f3f; for(int i=1;i<=n;i++) { if(tot+a[i].Ti>a[i].Si) { flag=1;break; } tot+=a[i].Ti; ans=min(ans,a[i].Si-tot); } if(flag) printf("-1\n"); else printf("%d\n",ans); fclose(stdin);fclose(stdout); return 0; }
2 小 a 的强迫症
qiang.in/.out/.cpp
2.1 问题描述
小 a 是一名强迫症患者,现在他要给一群带颜色的珠子排成一列,现在
有 N 种颜色,其中第 i 种颜色的柱子有 num(i) 个。要求排列中第 i 种颜色
珠子的最后一个珠子,一定要排在第 i+1 种颜色的最后一个珠子之前。问
有多少种排列珠子的方案。
2.2 输入格式
第一行一个整数 N,表示珠子颜色数量
第二行 N 个整数,分别表示每种珠子的颜色数量
2.3 输出格式
排列方案数,对 998244353 取余
2.4 样例输入
3
2 2 1
2.5 样例输出
3
2.6 数据规模及约定
共 3 种排列方案:
1 2 1 2 3
1 1 2 2 3
2 1 1 2 3
对于 40% 的数据,所有珠子数量和小于 15
对于 80% 的数据,N <= 1000,所有珠子数量和小于 5000
对于 100% 的数据,N <= 100000,所有珠子数量和小于 500000
/* 又是组合数取模问题。开始dp写的,写wa了...... sum[i]为前缀和,num[i]为i颜色的数量 那么i这种颜色对答案的贡献就是C(sum[i]-1,num[i]-1)%mod; 因为i的最后一个不能放到i+1最后一个的前面,所以要减一 分步乘法原理。 */ #include<iostream> #include<cstdio> #include<cstring> #define N 1000007 #define mod 998244353 #define ll long long using namespace std; ll n,m,ans,cnt; ll f[N]={1,1},fac[N]={1,1},inv[N]={1,1}; ll num[N],sum[N]; inline ll read() { ll x=0,f=1;char c=getchar(); while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } void init() { for(int i=2;i<=N;i++) { fac[i]=(fac[i-1]%mod*i%mod)%mod; f[i]=(mod-mod/i)*f[mod%i]%mod; inv[i]=inv[i-1]*f[i]%mod; } } ll C(int a,int b) { if(a<b) return 1; return fac[a]%mod*inv[b]%mod*inv[a-b]%mod; } int main() { freopen("qiang.in","r",stdin); freopen("qiang.out","w",stdout); n=read(); for(int i=1;i<=n;i++) num[i]=read(),sum[i]=sum[i-1]+num[i]; init();ans=1; for(int i=2;i<=n;i++) { ans=(ans%mod*C(sum[i]-1,num[i]-1)%mod)%mod; ans%=mod; } printf("%I64d\n",ans%mod); fclose(stdin);fclose(stdout); return 0; }
3 函数求和
sum.in/.out/.cpp
3.1 问题描述
你有一个含 N 个数字的数组 A,元素标号 1 到 N,同时他也有 N 个函
数,也标号 1 到 N。
第 i 个函数会返回数组中标号 L i 和 R i 之间的元素的和。
现在有以下两种询问:
1 x y 将数组的第 x 个元素修改为 y。
2 m n 询问标号在 m 和 n 之间的函数的值的和。
3.2 输入格式
输入数据第一行包含一个整数 N,表示数组的长度和函数的数量。
接下来的一行包含 N 个整数,表示数组中的元素 A i 。
接下来的 N 行,每行包含两个整数 L i ,R i ,表示一个函数。
接下来一行包含一个整数 Q,表示询问次数。
下面 Q 行,每行一个询问,格式见题目描述。
3.3 输出格式
对于每个第 2 类询问,输出相应的答案。
3.4 样例输入
5
1 2 3 4 5
1 3
2 5
4 5
3 5
1 2
4
2 1 4
1 3 7
2 1 4
2 3 5
4
3.5 样例输出
41
53
28
3.6 数据规模及约定
对于前 20% 的数据: N ≤ 1000,Q ≤ 1000
对于另外 30% 的数据: R i − L i ≤ 10, 所有的 x 各不相同
对于 100% 的数据: 1 ≤ N ≤ 10 5 , 1 ≤ L i ≤ R i ≤ N, 1 ≤ x ≤ N,
1 ≤ m ≤ n ≤ N, 1 ≤ A i ,y ≤ 10 9 , 1 ≤ Q ≤ 10 5
/* 题目来源 codechef NOV14.FNCS Chef and Churu 80分 黔驴技穷了 比着std写的 std不知为何 0分啊我也很绝望。 对于每个fi,可以直接使用树状数组求出。 所以我们可以使用分块,中间的直接用块的答案,边上的用树状数组。 首先我们进行预处理,记录第i块中每个编号的个数,这里用前缀和,并求出每个块的和。 对于修改操作1 x y,我们要维护树状数组和块状数组。 树状数组:直接维护。 块状数组:找到每个块中x的个数,这块的sum加上x*(y-a[x])。 最后把a[x]赋成y。 对于查询操作2 x y。 中间的块我们直接用块状数组的答案,O(√n)。 边上的两块我们用树状数组暴力求所有的f[i],O(√n log n)。 所以总的时间复杂度为O(n √n log n)。 */ #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #define ll long long #define N 100007 #define S 400 using namespace std; int n,m,unit,num; int fl[N],fr[N],a[N]; int cnt[S][N]; ll ta[N],sumb[S]; inline int read() { int x=0,f=1;char c=getchar(); while(c>‘9‘||c<‘0‘){if(c==‘-‘)f=-1;c=getchar();} while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘;c=getchar();} return x*f; } inline int lowbit(int x){return x&-x;} inline void ins(int i,int add) { for(;i<=n;i+=lowbit(i)) ta[i]+=add; } inline void update(int x,int y) { ins(x,y-a[x]); for(int i=1;i<=num;i++) sumb[i]+=(ll)cnt[i][x]*(y-a[x]); a[x]=y; } inline ll getsum(int i) { ll sum=0; for(;i;i-=lowbit(i)) sum+=ta[i]; return sum; } ll query(int l,int r) { int lblock=(l-1)/unit+1,rblock=(r-1)/unit+1;ll sum=0; if(lblock==rblock) for(int i=l;i<=r;i++) sum+=getsum(fr[i])-getsum(fl[i]-1); else { for(int i=lblock+1;i<=rblock-1;i++) sum+=sumb[i]; for(int i=l;i<=lblock*unit;i++) sum+=getsum(fr[i])-getsum(fl[i]-1); for(int i=(rblock-1)*unit+1;i<=r;i++) sum+=getsum(fr[i])-getsum(fl[i]-1); }return sum; } int main() { freopen("sum.in","r",stdin); freopen("sum.out","w",stdout); n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) fl[i]=read(),fr[i]=read(); for(int i=1;i<=n;i++) ins(i,a[i]); int nowblock=0; unit=(int)sqrt(n),num=unit+(unit*unit!=n); for(int i=1;i<=n;i++) { if(i%unit==1) nowblock++; cnt[nowblock][fl[i]]++; cnt[nowblock][fr[i]+1]--; } for(int i=1;i<=num;i++) for(int j=1;j<=n;j++) { cnt[i][j]+=cnt[i][j-1]; sumb[i]+=(ll) cnt[i][j]*a[j]; } int k,x,y; m=read(); for(int i=1;i<=m;i++) { k=read();x=read();y=read(); if(k==1) update(x,y); else printf("%I64d\n",query(x,y)); } fclose(stdin);fclose(stdout); return 0; }