根据解题顺序写的
A-Array of Discord
题意:修改一个数字里的一位,使序列变无序
思路:既然要改,就改成最小or最大,也就是0/1/9(注意不能出现前导0)
//-------这是用数字做的------用字符串也可以做,string可以直接比大小
ll a[105];
int n;
//是否满足要求(非按序)
bool check(int x){
for(int i=max(1,x-2);i<min(n,x+2);i++){
if(a[i] >a[i+1]) return 1;
}
return 0;
}
void solve(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
ll w=1;
//修改成1/0/9 验证即可
while(w<=a[i] || (w==1 && a[i]==0)){
for(int j=0;;){
if(w*10 > a[i] && j==0 && w>1){//第一位 且a[i]大于9
j=1;
continue;
}
//a[i]%w 剩下几位的数
//(a[i]/w - (a[i]/w)%10 + j) 前几位的数 把w对应的位改成(0、1、9)
ll x= (a[i]/w - (a[i]/w)%10 + j) * w + a[i]%w;
ll y=a[i];
a[i]=x;
if(check(i)){
for(int k=1;k<=n;k++){
cout<<a[k]<<" ";
}
cout<<endl;
return;
}
a[i]=y;//失败的话 回到原样
if(j==0) j=1;
else if(j==1) j=9;
else break;
}
w*=10;//每次×10 ,等于十进制往左一位
}
}
cout<<"impossible"<<endl;
}
M-Methodic Multiplication
题意:用皮亚诺算两个自然数相乘
本场签到题,手算找规律系列
或者说就是自然数相乘,只要知道皮亚诺是每加一层S()就+1 就可以,直接x*y然后转化成皮亚诺的格式
void solve(){
string s1,s2;
cin>>s1>>s2;
int cnt1=0,cnt2=0;
for(int i=0;i<s1.size();i++){
if(s1[i]=='S') cnt1++;
}
for(int i=0;i<s2.size();i++){
if(s2[i]=='S') cnt2++;
}
string ans;
int cnt=cnt2*cnt1;
for(int i=0;i<cnt;i++){
ans+="S(";
}
ans+="0";
for(int i=0;i<cnt;i++){
ans+=")";
}
cout<<ans<<endl;
}
G-Gig Combinatorics
题意:给定序列,问形如 “12…23"的子序列有多少种
注意到结尾必然是一个3,所以我们可以每遇到一个3就更新一次ans
当1、3固定时,设他们中间有k个2,可以知道有2^k-1个子序列满足要求,
即 2×2×2…×2×1-1
1 | 2 | 1 | 2 | 1 | 2 | 3 |
---|
若序列如上,就有2×2×2×1-1 + 2×2×1-1 + 2×1-1 种子序列,
经过化简,有(((1×2)+1)×2+1)×2)- 3
再举个栗子
1 | 2 | 2 | 1 | 1 | 2 | 3 |
---|
若序列如上,就有2×2×2×1-1 + 2×1-1 + 2×1-1 种子序列,
经过化简,有(((1×2)×2+1)+1 ×2)- 3
所以我们可以累计1的数量,每遇到一个3就减去此前遇到了的1的数量。
每遇到一个2,cnt×2;
遇到1时,cnt+1;
const int mod=1000000007;
void solve(){
ll n;
cin>>n;
int p1=0;
ll ans=0;
int x;
ll cnt=0;
for(int i=1;i<=n;i++){
cin>>x;
if(x==1){
cnt++;
cnt%=mod;
p1++;
}
else if(x==2){
cnt*=2;
cnt%=mod;
}
else{
ans+=cnt;
ans%=mod;
ans=(ans-p1+mod);
ans%=mod;
}
}
cout<<ans<<endl;
}
C-Coin Stacks
题意:给n堆硬币,每次从不同的堆分别取一枚,问能不能取完,能的话给出每次取的堆。
思路:先考虑什么情况取不完,①每次取两枚,那必定取走的总数是偶数 ② 每次要从不同的堆里取,如果有一堆比其他所有加起来都多,最后肯定都会取到这一堆
我们可以贪心地 每次取最多的的两堆,此时要考虑怎么维护一个有序序列
然后注意到 n不超过50,所有硬币加起来不超过1000 。成功的话是取总数/2次,那么也就是不超过500次。 直接用数组或者vector每次排序就可以
.
想过set,但是set是去重的,而我们这个会有重复,所以不适用orz
struct po{
int num;
int id;
}a[105];
bool cmp(po x, po y){
return x.num>y.num;
}
int n;
void solve(){
cin>>n;
int sum=0,maxx=0;
for(int i=1;i<=n;i++){
cin>>a[i].num;
a[i].id=i;
sum+=a[i].num;
}
sort(a+1,a+1+n,cmp);
maxx=a[1].num;
if(sum%2 || maxx>sum/2) {
cout<<"no\n";
return;
}
cout<<"yes"<<endl;
int p=1,pp=2;
for(int i=1;i<=sum/2;i++){
sort(a+1,a+1+n,cmp);
cout<<a[p].id<<" "<<a[pp].id<<endl;
a[p].num--;
a[pp].num--;
}
}
下班,剩下的等比赛结束的正答(趴
----------------------------补题分界线----------------------
D-Damsindistress
题意:给定每个大坝先有水量以及总容量,超过总容量时就会流向下一级(靠近根)的大坝。问最少需要多少新的水可以使整个大坝体系的根崩溃?
每个大坝都有它的下一级,从"树"的角度看也就是它的父亲,如果一个大坝i的父亲p[i]需要 f[p[i]] 的水量可以达成冲破营地的目标,那么 f[p[i]] 的水也可以是从i流向p[i],使它的父亲达成目标。
而i的水要流向p[i]要满足 : f[i] >= c[i] - u[i]
同时为了让p[i]可以冲破营地,要保证 : f[i]+u[i]>=f[p[i]
所以得到: f[i]=c[i]-u[i]+max(0,f[p[i]]-c[i])
ll p[400005],c[400005],u[400005],f[400005];
int main (){
int n,w;
cin>>n>>w;
for(int i=1;i<=n;i++){
cin>>p[i]>>c[i]>>u[i];
}
f[0]=w;
ll ans=f[0];
for(int i=1;i<=n;i++){
f[i]=c[i]-u[i]+max(0ll,f[p[i]]-c[i]);
ans=min(f[i],ans);
}
cout<<ans<<endl;
}
J-Joining Flows
题意:巧克力工厂有k个流出温度为t, 流量可在[a,b]间调节的巧克力水龙头。 其融合成的巧克力流量为每个水龙头的流量之和,
温度为每个水龙头温度和流量的加权平均值,
给出r种巧克力,问能否制成
题解: 显然我们有以下的结论:
①巧克力工厂的流量有最大值和最小值,不在此区间的肯定无法制成
②温度方面,温度加权式中ti是固定的,而xi可以分解成ai+ni。故可以提取出ai*ti的求和作为固定部分,浮动部分ni另行计算
③水龙头之间没有顺序之分,所以可以直接进行排序(温度),通过生序or降序求出剩余需要的流量可生成温度的最小值mint和最大值maxt
④根据温度加权的式子算出最后生成温度的最小值和最大值,若题目所给温度位于此区间则输出yes,反之输出no
不得不注意的是,记得转double
struct tap{
int t,a,b;
}p[15];
bool cmp(tap x, tap y){
return x.t<y.t;
}
int main(){
int k,r;
cin>>k;
ll maxf=0,minf=0,mst=0;
for(int i=1;i<=k;i++){
cin>>p[i].t>>p[i].a>>p[i].b;
maxf+=p[i].b;
minf+=p[i].a;
mst+=p[i].a*p[i].t;
}
sort(p+1,p+1+k,cmp);
cin>>r;
int t,f;
while(r--){
cin>>t>>f;
if(f<minf || f>maxf){
cout<<"no\n";
continue;
}
double tmp=f-minf;
double maxt=0,mint=0;
for(int i=1;i<=k;i++){
if(double(p[i].b - p[i].a) <= tmp){
tmp-=double(p[i].b - p[i].a);
mint+=p[i].t*double(p[i].b - p[i].a);
}
else{
mint+=p[i].t*tmp;
break;
}
}
tmp=f-minf;
for(int i=k;i>=1;i--){
if(double(p[i].b - p[i].a) <= tmp){
tmp-=double(p[i].b - p[i].a);
maxt+=p[i].t*double(p[i].b - p[i].a);
}
else{
maxt+=p[i].t*tmp;
break;
}
}
double minn=(mint+mst)/f;
double maxx=(maxt+mst)/f;
if(double(t)>=minn&&(double)t<=maxx){
cout<<"yes\n";
}
else cout<<"no\n";
}
}