Oracle
曾经有一位国王,统治着一片未名之地。他膝下有三个女儿。 三个女儿中最年轻漂亮的当属Psyche。她的父亲不确定她未来的命运,于是他来到Delphi神庙求神谕。 神谕可以看作一个不含前导零的正整数 n n。 为了得到真正的预言,他可以将 n n的各个数位重新排列,并将其分成两个不含前导零的正整数。 请你帮助他求出这两个正整数最大的和。如果不存在这样的两个正整数,输出"Uncertain".
第一行一个整数T T (1≤T≤10) (1 le T le 10) ,代表数据组数。 接下来T T T行,每行一个正整数n n (1≤n<1010000000) (1 le n < 10 ^ {10000000}) 。
对于每组数据,输出一个整数表示最大的和。若不存在一种方案,输出"Uncertain".
3 112 233 1
22 35 Uncertain
对于第一组数据,最优方案是将112 112 分成21 21 和1 1 ,最大的和为21+1=22 21 + 1 = 22 。 对于第二组数据,最优方案是将233 233 分成2 2 和33 33 ,最大的和为2+33=35 2 + 33 = 35 。 对于第三组数据,显然无法将一个数位分成两部分。 建议使用效率较高的读入方式。分析:
Provider : cxzxxjd
先记录 0−90-9这1010个数字分别有多少个。不难看出,最小的一个存在的数字和其余的数字降序排列的相加就是答案,但是最小的那个数字不能是00,因为题面上说明是正整数。将这两个数加起来时,注意处理进位问题。考虑无解的情况,即一串数字中仅存在11个非00数字或不存在。(PS.这道题目原本的时限是1s,考虑到题目的难度和评测机的问题,开了4s4s,大家可以自己在FST以后看一下时间。如果是时限是1s1s的话,sortsort是过不了的,输出也需要优化一下)
时间复杂度 O(Tn)O(Tn)。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=100000000+9; int a[N],b[N]; char s[N]; int main() { //freopen("f.txt","r",stdin); int T;scanf("%d",&T); while(T--){ scanf("%s",s); int n=strlen(s); for(int i=0;i<n;i++){ a[i]=s[i]-'0'; } sort(a,a+n); int i; for(i=0;i<n;i++){ if(a[i]!=0)break; } if(n-i<=1){ printf("Uncertain ");continue; } int t=0; for(int j=0;j<n;j++){ if(j!=i)b[t++]=a[j]; } int j;b[n-1]=0; t=a[i]; for(j=0;j<n;j++){ if(b[j]+t>9)b[j]=b[j]+t-10,t=1; else{b[j]=b[j]+t;break;} } if(b[n-1]==0)n--; for(i=n-1;i>=0;i--)printf("%d",b[i]); printf(" "); continue; } return 0; }
Arrange
Cupid一不小心将爱情之箭射到了自己,他爱上了Psyche。 这引起了他的母亲Venus的注意。Venus将Psyche带到了一堆打乱的谷堆旁。 这儿共有n n 堆稻谷,编号为1 1 到n n 。Psyche需要将这些谷堆以某种顺序排列,设最终排在第i i i位的谷堆是Ai A_i 她得知了一些该排列的要求: 1. 对于任意整数i∈[1,n] i in [1,n] ,A1,A2,...,Ai的最小值为Bi B_i 。 2. 对于任意整数i∈[1,n] i in [1,n] ,A1,A2,...,Ai的最大值为Ci C_i 。 现在Psyche想知道,共有多少种合法的排列。由于答案可能很大,输出时对998244353 998244353 取模。
第一行,一个整数T T (1≤T≤15) (1 le T le 15) ,代表数据组数。 对于每组数据,第一行有一个整数n n (1≤n≤105) (1 le n le 10 ^ 5) ,代表排列大小。 第二行,n n 个整数,第i i 个整数为Bi B_i (1≤Bi≤n) (1 le B_i le n) 。 第三行,n n 个整数,第i i 个整数为Ci C_i (1≤Ci≤n) (1 le C_i le n) 。
输出T T 行,对于每组数据输出答案对998244353 998244353 取模的结果。
2 3 2 1 1 2 2 3 5 5 4 3 2 1 1 2 3 4 5
1 0
对于第一组数据,只有一种合法的排列(2,1,3) (2,1,3) 。
对于第二组数据,没有合法的排列。
分析:Provider : frank_c1
首先,根据题意可得B数组应是单调不升的,C数组是单调不降的。
可以发现A1=B1=C1,所以如果B1≠C1 B_1 eq C_1 无解。
进一步,我们发现如果Bi<Bi−1 B_i < B_{i-1} ,Ai=Bi;如果Ci>Ci−1 C_i > C_{i-1} ,Ai=Ci A_i = C_i 。但是如果Bi<Bi−1和Ci>Ci−1 C_i > C_{i-1} 同时满足,就会产生冲突导致无解。
考虑Bi=Bi−1 B_i = B_{i-1} 和Ci=Ci−1 C_i = C_{i-1} 同时满足的情况,此时应有Ai∈(Bi,Ci) A_i in (B_i,C_i) 且Ai A_i 没有在之前使用过。因为(Bi,Ci) (B_i,C_i) 是不断变大的,我们只需维护一下这个区间内有多少值已经被使用过了,用乘法原理统计答案即可。注意到如果某时刻Ai A_i 没有值可以使用,也会导致无解。
时间复杂度O(Tn) O(Tn) 。
#include<cstdio> using namespace std; const int mod=998244353; const int N=1e5+9; int a[N],b[N],c[N]; int main() { //freopen("f.txt","r",stdin); int T;scanf("%d",&T); while(T--){ int n;scanf("%d",&n); for(int i=0;i<n;i++)scanf("%d",&b[i]); for(int i=0;i<n;i++)scanf("%d",&c[i]); int minn=b[0],maxn=c[0]; if(b[0]!=c[0]){printf("0 ");continue;} int ans=1; int i,num=0; for(i=1;i<n;i++){ if(b[i]==minn&&c[i]==maxn&&num>=0)ans=1LL*ans*num%mod,num--; else if(minn>b[i]&&c[i]==maxn)num+=minn-b[i]-1,minn=b[i]; else if(maxn<c[i]&&b[i]==minn)num+=c[i]-maxn-1,maxn=c[i]; else break; } if(i<n)printf("0 "); else printf("%d ",ans); } return 0; }
Wool
黎明时,Venus为Psyche定下了第二个任务。她要渡过河,收集对岸绵羊身上的金羊毛。 那些绵羊狂野不驯,所以Psyche一直往地上丢树枝来把它们吓走。地上现在有n n 根树枝,第i i i根树枝的长度是ai a_i . 如果她丢的下一根树枝可以和某两根树枝形成三角形,绵羊就会被激怒而袭击她。 现在Psyche手中只有长度不小于L L L且不大于R R 的树枝。请你帮忙计算,她下一根可以丢多少种不同长度的树枝而不会把绵羊激怒呢?
第一行,一个整数T(1≤T≤10) T (1 le T le 10) ,代表数据组数。 对于每组数据,第一行有三个整数n,L,R n,L,R (2≤n≤105,1≤L≤R≤1018) (2 le n le 10 ^ 5, 1 le L le R le 10 ^ {18}) 。 第二行,n n 个整数,第i i 个整数为ai a_i (1≤ai≤1018) (1 le a_i le 10 ^ {18}) ,代表第i i i根树枝的长度。
输出T T T行,对于每组数据,输出选取方式总数。
2 2 1 3 1 1 4 3 10 1 1 2 4
2 5
对于第一组数据,可以选用长度为2,2, 3 33333的树枝。 对于第二组数据,可以选用长度为6,7,8,9,10的树枝。分析:
Provider : frank_c1
考虑三角形三条边a,b,c
(a≥b) (a ge b) 的关系a−b<c,a+b>c
a - b < c, a + b > c ,即c∈(a−b,a+b)
c in (a-b,a+b)
令加入的边为c c ,枚举所有边作为a a 的情况。对于所有可行的b b ,显然与a a 相差最小的可以让(a−b,a+b) (a-b,a+b) 覆盖范围最大,所以可以贪心地选择不大于a a 的最大的b b 。
于是我们可以先将边按长度排序,然后ai和ai+1建一条线段。线段并是不合法的部分。
将所有线段按左端点排序,按序扫描一遍,过程中统计答案即可。
时间复杂度O(Tn logn) O(Tn log n) 。
#include<cstdio> #include<algorithm> using namespace std; const int mod=998244353; const int N=1e5+9; typedef long long ll; typedef pair<ll,ll>pll; pll p[N]; ll a[N],L,R; int n; int main() { int T;scanf("%d",&T); while(T--){ scanf("%d%I64d%I64d",&n,&L,&R); for(int i=0;i<n;i++)scanf("%I64d",&a[i]); sort(a,a+n); for(int i=0;i<n-1;i++){ p[i].first=a[i+1]-a[i]; p[i].second=a[i+1]+a[i]; } sort(p,p+n-1); ll x=L,ans=0; for(int i=0;i<n-1;i++){ if(p[i].first>=x)ans+=p[i].first-x+1; x=max(x,p[i].second); } if(R-x+1>0)ans+=R-x+1; printf("%I64d ",ans); } return 0; }