考试思路
今天考试情况不好,策略上还存在问题,内存定义的问题又出现了,看来还是不能放松啊,第一题没有开long long 直接从80掉到20,第二题超内存本来可以搞到的35分直接爆0,啊~本来可以有100多分的,看来还是自己能力有欠缺啊,还是要多多向大佬学习,好好改正才是,至于解题策略,还是要力求第一题要稳才是,太大意只会1分没有
第一题
题面
定义”组合数”S(n,m)代表将 n 个不同的元素拆分成 m 个非空集合的方案数.举个栗子,将{1,2,3}拆分成 2 个集合有({1},{2,3}),({2},{1,3}),({3},{1,2})三种拆分方法.
小猫想知道,如果给定 n,m 和 k,对于所有的 0<=i<=n,0<=j<=min(i,m),有多少对(i,j),满足 S(i,j)是 k 的倍数.
注意,0 也是 k 的倍数,S(0,0)=1,对于 i>=1,S(i,0)=0.
输入格式
从 problem.in 种读入数据
第一行有两个整数 t,k,t 代表该测试点总共有多少组测试数据.
接下来 t 行,每行两个整数 n,m.
输出格式
输出到文件 problem.out 中t 行,每行一个整数代表所有的 0<=i<=n,0<=j<=min(i,m),有多少对(i,j),满足 S(i,j)是 k 的倍数.
样例输入 1
1 2
3 3
样例输出 1
3
AC思路
这道题其实思路比较简单,方程也比较好推,s(i,j)=s(i-1,j-1)+s(i-1,j)*j,然而没有发现数据会爆long long 忘记对K随时取%,于是。。。唉,然后如果纯暴力是会T掉2个点的,要处理一个前缀和才行
代码
#include<iostream>
#include<cstdio>
using namespace std;
long long t,k;
long long xuan[3000][3000];
long long fan[3000][3000];
long long ans=0;
int main()
{
//freopen("problem.in","r",stdin);
//freopen("problem.out","w",stdout);
scanf("%lld%lld",&t,&k);
xuan[0][0]=1;
for(int i=1;i<=2000;i++)
for(int j=1;j<=i;j++)
{
xuan[i][j]=(xuan[i-1][j-1]+xuan[i-1][j]*j)%k;
}
fan[0][0]=1;
for(int i=1;i<=2000;i++)
{
ans=0;
for(int j=0;j<=2000;j++)
{
if(j<=i&&xuan[i][j]==0)
ans++;
fan[i][j]=fan[i-1][j]+ans;
}
}
for(long long i=1;i<=t;i++)
{
long long a,b;
scanf("%lld%lld",&a,&b);
cout<<fan[a][b]<<endl;
}
}
第二题
题面
信息组最近猫成灾了!隔壁物理组也拿猫没办法.信息组组长只好去请神刀手
来帮他们消灭猫.
信息组现在共有 n 只猫(n 为正整数),编号为 1 到 n,站成了一个环,第 i 只猫的左边是第i-1 只猫,右边是第 i+1 只猫.特别的,第 1 只猫的左边是第 n 只猫,第 n 只猫的右边是第 1只猫.每只猫拥有价值,表示消灭它能给信息组组长带来的声誉.
注意,有的猫价值为负数,这意味着消灭它会损害组长的声誉.
神刀手可以选择一些猫消灭掉.但是,我们的组长实际上非常喜欢猫,他希望神刀手不要消灭两只相邻的猫.
神刀手的能力组长现在还不知道.所以,组长希望知道对于所有的 1<=m<=n/2,如果神刀手刚好消灭 m 只猫,他最多能获得的声誉.
信息组组长当然知道怎么做啦!但是他想考考你……
输入格式
从 cat.in 中读入数据
第一行包括一个正整数 n
第二行为 n 个整数,依次代表第 1,2,…,n 只猫的价值.
输出格式
输出到文件 cat.out
输出共 n/2 行,第 i 行表示假如神刀手刚好消灭 i 只猫,信息组组长最多能获得
的收益.
样例输入1
8
1 1 8 1 1 9 1 1
样例输出1
9
17
18
12
AC思路
假如消灭某一只猫的收益大于与它相邻的两只猫的收益时,那么假如不消灭这一只猫,就一定要消灭与它相邻的两只猫。所以我们可以强制消灭这一只猫,并把相邻的与它两只猫缩成一只猫,权值为相邻的那两只猫的收益和-这只猫的收益。发现,假如再消灭缩出来的那只猫,那么收益就相当于只消灭相邻的猫的收益,并且消灭的猫数增加 1.发现这时候原问题转化成了 n-2,m-1 规模的子问题。
于是,我们每次可以消灭所有猫中收益最高的那只猫,并把与它相邻的猫缩起来即可。因为最优解一定满足前面的性质,所以可以这么贪心地做。
代码
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
long long n;
long long h[405000];
long long ans=0;
long long las[400500];
long long nex[400500];
long long num=0;
long long vis[400500];
struct node
{
long long biao;
long long jia;
};
bool operator < (const node &a,const node &b){
return a.jia<b.jia;
}//重载运算符
priority_queue<node>q;
int main()
{
scanf("%lld",&n);
long long m=n/2;
for(long long i=1;i<=n;i++)
{
cin>>h[i];
if(i==1)las[i]=n;
else las[i]=i-1;
if(i==n)nex[i]=1;
else nex[i]=i+1;
node l;
l.biao=i;
l.jia=h[i];
q.push(l);
}
num=n;
node st;
for(long long i=1;i<=m;i++)
{
st=q.top();
q.pop();
while(!q.empty()&&vis[st.biao])//找到没有消灭的
{
st=q.top();
q.pop();
}
ans+=st.jia;//消灭最大声誉的猫
vis[st.biao]=1;//消灭完了;
vis[nex[st.biao]]=1,vis[las[st.biao]]=1;
num++;
h[num]=h[las[st.biao]]+h[nex[st.biao]]-h[st.biao];//把前后两只猫合并为一只,存入利润差;
nex[num]=nex[nex[st.biao]],las[nex[num]]=num;
las[num]=las[las[st.biao]],nex[las[num]]=num;
node l;
l.jia=h[num];
l.biao=num;
q.push(l);
printf("%lld\n",ans);
}
}