虽然已经是TG选手了,但是作为一个初中生还是要做做PJ哒>_<.
T1:
题目:luogu5015.
题目大意:将输入的字符中的小写字母、大写字母和数字的总数量输出.
水题,用getchar水过就可以了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
int sum;
Abigail into(){
char c=getchar();
while (c!=EOF){
if (c<='Z'&&c>='A'||c<='z'&&c>='a'||c<='9'&&c>='0') ++sum;
c=getchar();
}
}
Abigail outo(){
printf("%d\n",sum);
}
int main(){
into();
outo();
return 0;
}
T2:
题目:luogu5016.
题目大意:给定一个数组A,现在在第m个点前的都属于龙,后面的都属于虎,第m个不属于任意一方.现在给Ai加了s1,要求再给一个Aj加s2,使得两方气势差最小.其中一方的气势定义为.
其实这道题就是算出两方的气势,然后暴力枚举加入的位置就可以了.
不懂为什么一群人说被long long坑了,这不是明显要开long long吗...
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
const LL INF=(1LL<<63)-1LL; //写成1LL<<60的我被卡精度了
LL a[N+9],sum1,sum2,a1,a2,ans;
int n,m,p,v;
Abigail into(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
scanf("%d%d%lld%lld",&m,&p,&a1,&a2);
}
Abigail work(){
a[p]+=a1;
for (int i=1;i<m;++i)
sum1+=a[i]*(m-i);
for (int i=m+1;i<=n;++i)
sum2+=a[i]*(i-m);
ans=INF;v=1;
for (int i=1;i<m;++i)
if (ans>abs(sum1+a2*(m-i)-sum2)) ans=abs(sum1+a2*(m-i)-sum2),v=i;
if (ans>abs(sum1-sum2)) ans=abs(sum1-sum2),v=m;
for (int i=m+1;i<=n;++i)
if (ans>abs(sum1-sum2-a2*(i-m))) ans=abs(sum1-sum2-a2*(i-m)),v=i;
}
Abigail outo(){
printf("%d\n",v);
}
int main(){
into();
work();
outo();
return 0;
}
T3:
题目:luogu5017.
题目大意:给定一辆车往返一趟的时间m,并且车的容量无限大.现在要送n个人,人i会在时刻ti到达车站,问车这n个人等车时间之和最小是多少.
据说可以以时间为状态,然后斜率优化一下可以做到,但是我不会.
我们可以设f[i]表示送前i个同学需要的最少等待时间,然后直接枚举从前面那个状态转移过来,可以做到.
但是很明显这个算法是不满足最优子结构的,因为总等待时间最短不一定代表回到起点的时间点最早.
我们考虑先预处理两个数组c[i]和s[i],分别表示到时刻i时的人的数量与乘客到达时间的前缀和.
那么我们考虑设f[i]表示时刻i发一辆车时的最少总等待时间,然后枚举上一次的发车时刻j来转移,时间复杂度.
对于这个算法,我们可以列出方程:
考虑一个状态f[i]从f[j]转移过来,可以发现若,明显可以让这两次发车之间多发一次车来使答案不会变得更劣,那么我们就可以将枚举j变成枚举时差来优化上面的算法,时间复杂度.
那么方程就变为:
继续考虑优化这个算法,发现一辆车的发车时间只会是,其中.那么我们可以只计算有用的状态,不去计算无用的状态,也就是说我们枚举到一个状态f[i]时,判断这个状态是否有一个t[j],使得,具体可以通过是否为0来判断.这样我们就可以做到.
然后貌似还可以把这个算法优化一下,类似于斜率优化,可以做到,但是我不会.
算法代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=500,M=100,T=5*1000000;
const int INF=(1<<29)-1;
int n,m,t[N+9];
int c[T+9],s[T+9],mt;
//int f[N+9][M*2+9];
int f[T+9];
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i){
scanf("%d",&t[i]);
mt=max(mt,t[i]);
++c[t[i]];s[t[i]]+=t[i];
}
}
Abigail work(){
mt+=m-1;
sort(t+1,t+1+n);
for (int i=1;i<=mt;++i)
c[i]+=c[i-1],s[i]+=s[i-1];
for (int i=0;i<=mt;++i)
f[i]=i*c[i]-s[i];
for (int i=0;i<=mt;++i){
if (!(c[i]-c[i-m])&&i>m){
f[i]=f[i-m]; //避免一些麻烦的处理
continue;
}
f[i]=i*c[i]-s[i];
for (int j=max(0,i-(m<<1));j<=i-m;++j)
f[i]=min(f[i],f[j]+i*(c[i]-c[j])-s[i]+s[j]);
}
}
Abigail outo(){
int ans=INF;
for (int i=t[n];i<=mt;++i)
ans=min(ans,f[i]);
printf("%d\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}
T4:
题目:luogu5018.
题目大意:给定一棵二叉树,要求一棵最大的子树,使得这棵子树翻转过后与原子树一模一样(点权、结构、大小等).
感觉很难的一道题,也没做过类似的题,看到题面吓懵了,PJ考的都是什么毒瘤题啊.
事实上,我们只要考虑以每个点为根,暴力判断这棵子树是否对称,并在判定的时候及时弹出.这样看起来是的,事实上是的.
为什么呢?首先我们在遍历的时候,每次判定,我们只要一旦发现就够不同就会弹出,那么很显然最坏的情况肯定是当一棵树是完全二叉树的时候.而完全二叉树的深度是的,我们在每一层都扫了一遍节点,所以时间复杂度为.
具体各种剪枝看代码:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=1000000;
int n,v[N+9],ls[N+9],rs[N+9],siz[N+9],ans;
void dfs(int k){
siz[k]=1;
if (ls[k]) dfs(ls[k]);
if (rs[k]) dfs(rs[k]);
siz[k]+=siz[ls[k]]+siz[rs[k]];
}
bool check(int r1,int r2){
if (r1+r2==0) return true; //若r1=r2=0,则匹配
if (v[r1]^v[r2]) return false; //两边点权是否相同
if ((siz[ls[r1]]^siz[rs[r2]])||(siz[rs[r1]]^siz[ls[r2]])) return false; //两边是否大小/结构对称
if (!check(ls[r1],rs[r2])) return false; //若r1的左儿子与r2的右儿子不匹配
if (!check(rs[r1],ls[r2])) return false; //若r1的右儿子与r2的左儿子不匹配
return true;
}
Abigail into(){
scanf("%d",&n);
for (int i=1;i<=n;++i) scanf("%d",&v[i]);
for (int i=1;i<=n;++i){
scanf("%d%d",&ls[i],&rs[i]);
if (ls[i]==-1) ls[i]=0;
if (rs[i]==-1) rs[i]=0;
}
}
Abigail work(){
dfs(1);
for (int i=1;i<=n;++i)
if (check(i,i)) ans=max(ans,siz[i]);
}
Abigail outo(){
printf("%d\n",ans);
}
int main(){
into();
work();
outo();
return 0;
}