蒟蒻池子琰的题解报告
考场预估:200
实际:130 主要是T2犯傻了,等下会详细讲解。
接下来开始正式讲题。
T1:
题意没什么好讲的,就是给序列规则,推公式。
题意:
你可以像我这样写出前面找规律加猜,也可以像另外巨佬一样推公式;
可得:
(前面x也用同样方法)
然后加上超大数的位数判断就可以完美输出了!!!(AC代码如下)
#include <bits/stdc++.h>
using namespace std;
long long n,m;
int main(){
freopen("math.in","r",stdin);
freopen("math.out","w",stdout);
cin>>n;
if(n<=31) cout<<((1<<n)-1);
else cout<<(long long)(n*log10(2.0));
return 0;
}
(虽然数据似乎出了点问题。。。。。。但是思想还是对的。)
T2:
首先我找到了这道题的原型:洛谷P5123 [USACO18DEC]Cowpatibility
和原题不大一样的是,这题让我们求每个人前面有几个朋友。
先说说我考场上的想法:(10分)
我十分天真地以为只要找扫到自己时出现次数做多的数就好了。
这种想法显得没有脑子,于是聪明的我们就不考虑了。
接下来是机智的正解:
我们需要用到容斥原理!(我们用on,tw,th,fo这四个数组分别表示这个数量的覆盖如图)
具体代码如下:(容斥原理的实现)
for(int i=1;i<=n;i++){
a=read(),b=read(),c=read(),d=read();
sort(x+1,x+5);这能省很多!
printf("%d\n",on[a]+on[b]+on[c]+on[d]-tw[a][b]-tw[a][c]-tw[a][d]-tw[b][c]-tw[b][d]-tw[c][d]+th[a][b][c]+th[a][b][d]+th[a][c][d]+th[b][c][d]-fo[a][b][c][d]);
on[a]++,on[b]++,on[c]++,on[d]++;
tw[a][b]++,tw[a][c]++,tw[a][d]++,tw[b][c]++,tw[b][d]++,tw[c][d]++;
th[a][b][c]++,th[a][b][d]++,th[a][c][d]++,th[b][c][d]++;
fo[a][b][c][d]++;
}
四个数组用途上面图都已经说明白了。
T3:
这题正解考试的时候没想出来。(反正贪心肯定错了)
题目大意:
每做一道题需要两 笔付款,第一笔 a[i](1<=a[i]<=m)元在做题的那一个月初支付,第二笔 b[i]元(1<=b[i]<=m)在 做完后的下一个月初支付。
本月的钱必须本月用掉。
输入工资,题目数;
求最少月数把全部题支付完;
这是一道DP题!!!
接下来说说正解吧:(听完了巨佬的讲解才知道的。。。。。。)
dp i j =k 表示 第i月 完成了j个任务 本月剩余k元
DP的话就直接上代码吧
(解释都在代码里!)
以下是核心代码:
dp[1][0]=m; 初始设置
for(int i=1;i<=n*2;i++){ 到了第i个月
for(int j=0;j<=n;j++){ 作业(任务)
if(dp[i][j]<0) break; 没钱了就走
int res1=dp[i][j],res2=m; 解释一下:res1是第一次付款的剩余res2是为第二次付款留钱
dp[i+1][j]=max(dp[i+1][j],m);剩下的钱越多越好,为了支付新的作业。
for(int k=j+1;k<=n;k++){ 选择作业
if(res1-a[k]<0||res2-b[k]<0) break; 没钱了走人
res1-=a[k],res2-=b[k]; 付掉了钱
dp[i+1][k]=max(dp[i+1][k],res2); 选择最优
}
}
}
(看来回去要好好练DP题了。)
T4:
这题需要用到树链剖分,蒟蒻还需回家研究
推荐一个学习网址:https://www.cnblogs.com/ivanovcraft/p/9019090.html
Zs的博客讲解:https://www.cnblogs.com/chhokmah/p/10387786.html
若全部dfs不优化60分;
回家继续写;