T1 入阵曲
背景
pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv
丹青千秋酿,一醉解愁肠。
无悔少年枉,只愿壮志狂。
题目描述
小 F 很喜欢数学,但是到了高中以后数学总是考不好。
有一天,他在数学课上发起了呆;他想起了过去的一年。一年前,当他初识算法竞赛的 时候,觉得整个世界都焕然一新。这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以 解决的问题,被一个又一个算法轻松解决。
小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢。
一年过去了,想想都还有点恍惚。
他至今还能记得,某天晚上听着入阵曲,激动地睡不着觉,写题写到鸡鸣时分都兴奋不 已。也许,这就是热血吧。
也就是在那个时候,小 F 学会了矩阵乘法。让两个矩阵乘几次就能算出斐波那契数列的 第 10^{100}10
100
项,真是奇妙无比呢。
不过,小 F 现在可不想手算矩阵乘法——他觉得好麻烦。取而代之的,是一个简单的小 问题。他写写画画,画出了一个 n \times mn×m 的矩阵,每个格子里都有一个不超过 kk 的正整数。
小 F 想问问你,这个矩阵里有多少个不同的子矩形中的数字之和是 kk 的倍数? 如果把一个子矩形用它的左上角和右下角描述为 (x_1,y_1,x_2,y_2)(x 1,y 1,x2,y 2 ),其中x_1 \le x_2,y_1 \le y_2x 1≤x2,y 1≤y 2;
输入输出格式
输入格式:
从标准输入中读入数据。
输入第一行,包含三个正整数 n,m,kn,m,k。
输入接下来 nn 行,每行包含 mm 个正整数,第 ii 行第 jj 列表示矩阵中第 ii 行第 jj 列 中所填的正整数 a_{i,j}a
i,j
。
输出格式:
输出到标准输出中。
输入一行一个非负整数,表示你的答案。
输入输出样例
输入样例#1:
2 3 2
1 2 1
2 1 2
输出样例#1:
6
说明
【样例 1 说明】
这些矩形是符合要求的: (1, 1, 1, 3),(1, 1, 2, 2),(1, 2, 1, 2),(1, 2, 2, 3),(2, 1, 2, 1),(2, 3, 2, 3)。
题解:
神奇式子:
sum[i][j]表示前i行,前j列总和
(sum[j][k]-sum[i][k])%modd=0时,sum[j][k]%modd=sum[i][k]%modd
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
long long n,m,modd,a[505][505],sum[505][505];
long long count[1000005],f[10000],ans=0;
inline void read(long long &x)
{
x=0;int f=1;char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
x*=f;
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&modd);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
scanf("%lld",&a[i][j]);
sum[i][j]=(sum[i-1][j]+a[i][j]+sum[i][j-1]-sum[i-1][j-1])%modd;
}
for(int i=0;i<n;i++)//枚举行
for(int j=i+1;j<=n;j++)
{
count[0]=1;
for(int k=1;k<=m;k++)
{
f[k]=(sum[j][k]-sum[i][k])%modd;
if(f[k]<0) f[k]=f[k]+modd;
ans=ans+count[f[k]];
count[f[k]]++;
}
for(int k=1;k<=m;k++)
count[f[k]]=0;
}
printf("%lld",ans);
}
T2 将军令
题目背景
pdf题面和大样例链接:http://pan.baidu.com/s/1cawM7c 密码:xgxv
历史/落在/赢家/之手
至少/我们/拥有/传说
谁说/败者/无法/不朽
拳头/只能/让人/低头
念头/却能/让人/抬头
抬头/去看/去爱/去追
你心中的梦
题目描述
又想起了四月。
如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房。
凭君莫话封侯事,一将功成万骨枯。
梦里,小 F 成了一个给将军送密信的信使。
现在,有两封关乎国家生死的密信需要送到前线大将军帐下,路途凶险,时间紧迫。小 F 不因为自己的祸福而避趋之,勇敢地承担了这个任务。
不过,小 F 实在是太粗心了,他一不小心把两封密信中的一封给弄掉了。
小 F 偷偷打开了剩下的那封密信。他 发现一副十分详细的地图,以及几句批文——原来 这是战场周围的情报地图。他仔细看后发现,在这张地图上标记了 n 个从 1 到 n 标号的 驿站,n − 1 条长度为 1 里的小道,每条小道双向连接两个不同的驿站,并且驿站之间可以 通过小道两两可达。
小 F 仔细辨认着上面的批注,突然明白了丢失的信的内容了。原来,每个驿站都可以驻 扎一个小队,每个小队可以控制距离不超过 k 里的驿站。如果有驿站没被控制,就容易产 生危险——因此这种情况应该完全避免。而那封丢失的密信里,就装着朝廷数学重臣留下的 精妙的排布方案,也就是用了最少的小队来控制所有驿站。
小 F 知道,如果能计算出最优方案的话,也许他就能够将功赎过,免于死罪。他找到了 你,你能帮帮他吗? 当然,小 F 在等待你的支援的过程中,也许已经从图上观察出了一些可能会比较有用的 性质,他会通过一种特殊的方式告诉你。
输入输出格式
输入格式:
从标准输入中读入数据。
输入第 1 行一个正整数 n,k,t,代表驿站数,一支小队能够控制的最远距离,以及特 殊性质所代表的编号。关于特殊性质请参照数据范围。
输入第 2 行至第 n 行,每行两个正整数 u_iu
i
,v_iv
i
,表示在 u_iu
i
和 v_iv
i
间,有一条长度为 一里的小道。
输出格式:
输出到标准输出中。
输出一行,为最优方案下需要的小队数。
输入输出样例
输入样例#1: 复制
4 1 0
1 2
1 3
1 4
输出样例#1: 复制
1
输入样例#2: 复制
6 1 0
1 2
1 3
1 4
4 5
4 6
输出样例#2: 复制
2
说明
【样例 1 说明】
如图。由于一号节点到周围的点距离均是 1,因此可以控制所有驿站。
题解:
需要提前建一个树,计算深度,从叶子节点向上找祖先,再回朔
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
int num;
int deep;
}a[400005];
int s=0,vis[400005],n,k,t,u[400005],v[400005],ans=0;
int first[400005],fa[400005],nextt[400005],tot[400005];
int cmp(const node a,const node b)
{
if(a.deep>b.deep) return 1;
return 0;
}
void build(int x)//建树
{ int y;
for(int i=first[x];i>0;i=nextt[i])
{
y=tot[i];
if(fa[x]!=y)
{
fa[y]=x;
a[y].num=y;
a[y].deep=a[x].deep+1;
build(y);
}
}
}
void add(int x,int y)
{
tot[++s]=y;
nextt[s]=first[x];
first[x]=s;
}
int find(int x,int k)
{ if(k==0)
return x;
else {
//vis[fa[x]]=1;
find(fa[x],k-1);
}
}
int dfs(int x,int fa,int k)
{ int y;
vis[x]=1;
if(k==0) return 0;
for(int i=first[x];i>0;i=nextt[i])
{
y=tot[i];
if(y!=fa)
dfs(y,x,k-1);
}
}
int main()
{
scanf("%d%d%d",&n,&k,&t);
for(int i=1;i<=n-1;i++)
{
scanf("%d%d",&u[i],&v[i]);
add(u[i],v[i]);
add(v[i],u[i]);
}
a[1].deep=1;a[1].num=1;
fa[1]=1;
build(1);
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{int zz;
if(!vis[a[i].num])
{ //vis[a[i].num]=1;
zz=find(a[i].num,k);
ans++;
dfs(zz,0,k);
}
}
printf("%d",ans);
}