CSP-S加赛0915
题面和题解
非常不解,当时考试最后10分钟的时候开始看的第2题,顺手打了一个 lca 加上暴力 dfs 还有个20分,不知道那些两个题都得0分的是怎么搞得.
A. 山洞
输出0就有40分,出题人竟如此良心.
明显是一个dp,可是我最开始看还是想着用组合数来着.
设dp[i][j]表示在第 i 步到达 j 的方案数. 由于第 i 步要走 i 个点,则转移很简单:
,
边界显然 dp[0][1]=dp[0][n-1]=1,记得 j-i 和 j+i 不要越界,加/减 n 就行了.
数组开不下,那就滚一下.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 10001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3))+((x<<1))+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,m;
ll kk,dp[2][maxn]/*滚动数组*/;
ll bzh/*变正*/(rll x) { while(x&LLONG_MIN) x+=n; return x; }
int main()
{
n=read();m=read();dp[0][1]=dp[0][n-1]=1;
for(rll i=2;i<=m;i++)
{
kk^=1;
for(rll j=0;j<n;j++) dp[kk][j]=(dp[kk^1][bzh(j-i)]+dp[kk^1][(j+i)%n])%mod;
}
write(dp[kk][0]);
return 0;
}
然后你就有了60分的好成绩.
详细信息
输入文件(cave1.in)
455 6
答案文件(cave1.out)
0
用户输出
0系统信息
Exited with return code 0输入文件(cave2.in)
349 6
答案文件(cave2.out)
0
用户输出
0系统信息
Exited with return code 0输入文件(cave3.in)
873 847
答案文件(cave3.out)
168562759
用户输出
168562759系统信息
Exited with return code 0输入文件(cave4.in)
641 312
答案文件(cave4.out)
184576581
用户输出
184576581系统信息
Exited with return code 0输入文件(cave5.in)
873 464
答案文件(cave5.out)
782238569
用户输出
782238569系统信息
Exited with return code 0输入文件(cave6.in)
501 256
答案文件(cave6.out)
618778073
用户输出
618778073系统信息
Exited with return code 0输入文件(cave7.in)
303 43643612
答案文件(cave7.out)
3328565
输入文件(cave8.in)
216 223365721
答案文件(cave8.out)
0
输入文件(cave9.in)
793 204192683
答案文件(cave9.out)
667243642
输入文件(cave10.in)
770 275829513
答案文件(cave10.out)
0
考虑优化. 发现中间的过程许多都是重复的,因此只需要求出前 n 步和后 m%n 的 dp 值,中间 部分直接矩阵快速幂即可.
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 10001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3))+((x<<1))+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,m;
ll kk,dp[2][maxn],tmp[maxn],ans[maxn]={1,0};
ll bzh/*变正*/(rll x) { while(x&LLONG_MIN) x+=n; return x; }
static inline void mulans()
{
for(rll i=0;i<n;i++) tmp[i]=ans[i],ans[i]=0;
for(rll i=0;i<n;i++) for(rll j=0;j<n;j++) ans[(i+j)%n]=(ans[(i+j)%n]+tmp[i]*dp[kk][j]%mod)%mod;
}
static inline void mula()
{
for(rll i=0;i<n;i++) tmp[i]=dp[kk][i],dp[kk][i]=0;
for(rll i=0;i<n;i++) for(rll j=0;j<n;j++) dp[kk][(i+j)%n]=(dp[kk][(i+j)%n]+tmp[i]*tmp[j]%mod)%mod;
}
static inline void ksm(rll b)
{
for(rll i=b;i;i>>=1) { if(i&1) mulans();mula(); }
for(rll i=0;i<n;i++) dp[0][i]=ans[i];
}
int main()
{
n=read();m=read();dp[0][1]=dp[0][n-1]=1;
for(rll i=2;i<=n;i++)
{
kk^=1;
for(rll j=0;j<n;j++) dp[kk][j]=(dp[kk^1][bzh(j-i)]+dp[kk^1][(j+i)%n])%mod;
}
ksm(/*dp[kk],*/m/n);kk=0;
for(rll i=1;i<=m%n;i++)
{
kk^=1;
for(rll j=0;j<n;j++) dp[kk][j]=(dp[kk^1][bzh(j-i)]+dp[kk^1][(j+i)%n])%mod;
}
write(dp[kk][0]);
return 0;
}
然后你有了80分的好成绩.
详细信息
输入文件(cave1.in)
455 6
答案文件(cave1.out)
0
用户输出
0系统信息
Exited with return code 0输入文件(cave2.in)
349 6
答案文件(cave2.out)
0
用户输出
0系统信息
Exited with return code 0输入文件(cave3.in)
873 847
答案文件(cave3.out)
168562759
用户输出
168562759系统信息
Exited with return code 0输入文件(cave4.in)
641 312
答案文件(cave4.out)
184576581
用户输出
184576581系统信息
Exited with return code 0输入文件(cave5.in)
873 464
答案文件(cave5.out)
782238569
用户输出
782238569系统信息
Exited with return code 0输入文件(cave6.in)
501 256
答案文件(cave6.out)
618778073
用户输出
618778073系统信息
Exited with return code 0输入文件(cave7.in)
303 43643612
答案文件(cave7.out)
3328565
用户输出
106605750Special Judge 信息
Files user_out and answer differ
系统信息
Exited with return code 0输入文件(cave8.in)
216 223365721
答案文件(cave8.out)
0
用户输出
0系统信息
Exited with return code 0输入文件(cave9.in)
793 204192683
答案文件(cave9.out)
667243642
用户输出
620222038Special Judge 信息
Files user_out and answer differ
系统信息
Exited with return code 0输入文件(cave10.in)
770 275829513
答案文件(cave10.out)
0
用户输出
0系统信息
Exited with return code 0可以发现,是 WA.
那么肯定是有哪里出错了.
在累加 dp 值的时候,如果出现当前点和下一个点正好在环的两端,即:

这种情况显然只需要加一遍就可以,所以加一个特判即可.
然后就可以愉快得 AC 了!
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define rg register
#define rll rg ll
#define maxn 10001
#define mod 1000000007
#define put_ putchar(' ')
#define putn putchar('\n')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3))+((x<<1))+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,m;
ll kk,dp[2][maxn],tmp[maxn],ans[maxn]={1,0};
ll bzh/*变正*/(rll x) { while(x&LLONG_MIN) x+=n; return x; }
static inline void mulans()
{
for(rll i=0;i<n;i++) tmp[i]=ans[i],ans[i]=0;
for(rll i=0;i<n;i++) for(rll j=0;j<n;j++) ans[(i+j)%n]=(ans[(i+j)%n]+tmp[i]*dp[kk][j]%mod)%mod;
}
static inline void mula()
{
for(rll i=0;i<n;i++) tmp[i]=dp[kk][i],dp[kk][i]=0;
for(rll i=0;i<n;i++) for(rll j=0;j<n;j++) dp[kk][(i+j)%n]=(dp[kk][(i+j)%n]+tmp[i]*tmp[j]%mod)%mod;
}
static inline void ksm(/*rll a[],*/rll b)
{
for(rll i=b;i;i>>=1) { if(i&1) mulans();mula(); }
for(rll i=0;i<n;i++) dp[0][i]=ans[i];
}
int main()
{
n=read();m=read();dp[0][1]=dp[0][n-1]=1;
for(rll i=2;i<=n;i++)
{
kk^=1;
for(rll j=0;j<n;j++)
if((j-i+n)%n==(i+j)%n) dp[kk][j]=dp[kk^1][(i+j)%n];
else dp[kk][j]=(dp[kk^1][bzh(j-i)]+dp[kk^1][(i+j)%n])%mod;
}
ksm(/*dp[kk],*/m/n);kk=0;
for(rll i=1;i<=m%n;i++)
{
kk^=1;
for(rll j=0;j<n;j++)
if((j-i+n)%n==(i+j)%n) dp[kk][j]=dp[kk^1][(i+j)%n];
else dp[kk][j]=(dp[kk^1][bzh(j-i)]+dp[kk^1][(i+j)%n])%mod;
}
write(dp[kk][0]);
return 0;
}
B.beauty
手模一下,可以轻易证明:
若每个点的子树(包括它自己)中关键点数量为 cnt[i],显然另一个方向中关键点数量为 k-cnt[i]. 那么答案就是:
.
因为每一个点的路径数加到一起必定是总的最多的路径数.
具体如果想要构造方法就是找出树的重心,从重心开始由近及远把 i 关键点与 i+k 配对.
点击查看代码
#include<bits/stdc++.h>
#ifndef ONLINE_JUDGE
#define ll long long
#define rg register
#define rll rg ll
#define maxn 100001
#define put_ putchar(' ')
#define putn putchar('\a')
using namespace std;
static inline ll read()
{
rll f=0,x=0;rg char ch=getchar();
while(ch<'0'||ch>'9') f|=(ch=='-'),ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3))+((x<<1))+(ch^'0'),ch=getchar();
return f?-x:x;
}
static inline void write(rll x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);putchar(x%10|'0');
}
ll n,k,ans;
vector<ll> g[maxn];
ll cnt[maxn];
bool fl[maxn];
static inline void dfs1(ll x,ll fa)
{
cnt[x]=fl[x];
for(rll i=0;i<g[x].size();i++)
{
rll to=g[x][i];if(to==fa) continue;
dfs1(to,x);cnt[x]+=cnt[to];
}
}
int main()
{
n=read();k=read();read();for(rll i=1;i<=(k<<1);i++) fl[read()]=1;
for(rll i=1,u,v;i<n;i++) u=read(),v=read(),g[u].push_back(v),g[v].push_back(u);
dfs1(1,0);
for(rll i=1;i<=n;i++) ans+=min(cnt[i],(k<<1)-cnt[i]);
write(ans);
return 0;
}
--END--

浙公网安备 33010602011771号
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/p/16698038.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!