洛谷——Day2

来源:互联网 发布:广州软件外包 编辑:程序博客网 时间:2024/05/25 08:13

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);}