[luogu模拟赛] 11.2

来源:互联网 发布:波司登淘宝旗舰店电话 编辑:程序博客网 时间:2024/05/21 08:57

//0 + 0 + 8
//qaq我太水了

入阵曲(rally)

【题目描述】
丹青千秋酿,一醉解愁肠。
无悔少年枉,只愿壮志狂。
小 F 很喜欢数学,但是到了高中以后数学总是考不好。
有一天,他在数学课上发起了呆;他想起了过去的一年。一年前,当他初识算法竞赛的
时候, 觉得整个世界都焕然一新。 这世界上怎么会有这么多奇妙的东西?曾经自己觉得难以
解决的问题,被一个又一个算法轻松解决。
小 F 当时暗自觉得,与自己的幼稚相比起来,还有好多要学习的呢。
一年过去了,想想都还有点恍惚。
他至今还能记得,某天晚上听着入阵曲,激动地睡不着觉,写题写到鸡鸣时分都兴奋不
已。也许,这就是热血吧。
也就是在那个时候, 小 F 学会了矩阵乘法。 让两个矩阵乘几次就能算出斐波那契数列的
第 10 100 项,真是奇妙无比呢。
不过,小 F 现在可不想手算矩阵乘法——他觉得好麻烦。取而代之的,是一个简单的小
问题。 他写写画画, 画出了一个 ? × ? 的矩阵, 每个格子里都有一个不超过 ? 的正整数。
小 F 想问问你,这个矩阵里有多少个不同的子矩形中的数字之和是 ? 的倍数?
如果把一个子矩形用它的左上角和右下角描述为 (? 1 ,? 1 ,? 2 ,? 2 ),其中? 1 ≤ ? 2 ,? 1 ≤ ? 2 ;
那么,我们认为两个子矩形是不同的,当且仅当他们以 (? 1 ,? 1 ,? 2 ,? 2 ) 表示时不同;也就是
说,只要两个矩形以 (? 1 ,? 1 ,? 2 ,? 2 ) 表示时相同,就认为这两个矩形是同一个矩形,你应该
在你的答案里只算一次。
【输入格式】
从文件 rally.in 中读入数据。
第一行,包含三个正整数 ?,?,?。
输入接下来 ? 行,每行包含 ? 个正整数,第 ? 行第 ? 列表示矩阵中第 ? 行第 ? 列
中所填的正整数 ? ?,? 。
【输出格式】
输出到文件 rally.out 中。
输入一行一个非负整数,表示你的答案。
【样例 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)。
【样例 2】
见选手目录下的 rally/rally2.in 与 rally/rally2.ans 。
【数据范围与约定】
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解
决一部分数据。
每个测试点的数据规模及特点如下表:
n <=400, m <= 400, k <= 1e6

//原本想打55分的前缀和
//结果打的太快错了好几个地方,也没有好好检查,爆了0

55分暴力解法

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 400 + 100;int a[maxn][maxn], sum[maxn][maxn];int n,m,k,ans = 0;int read() {    int x = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1;        ch = getchar();    }    while(ch >= '0' && ch <= '9') {        x = (x << 1) + (x << 3) + ch -'0';        ch =getchar();    }    return x * f;}bool pd(int x1, int y1, int x2, int y2) {    return ( sum[x1][y1] - sum[x1][y2] - sum[x2][y1] + sum[x2][y2] ) % k == 0;}int main() {    n = read(), m = read(), k = read();    for(int i = 1; i <= n; i++) {        for(int j = 1; j <= m; j++) {            a[i][j] = read();            sum[i][j] = (sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j]) % k;        }    }    for(int i = 1; i <= n; i++) {        for(int j = 1; j <= m; j++) {            for(int k = i; k <= n; k++) {                for(int l = j; l <= m; l++) {                    if(pd(k,l,i - 1,j - 1)) ans++;                }            }        }    }    cout<<ans<<endl;    return 0;}

正解优化了一维
(q - p) % k == 0
q % k == p % k
所以暴力枚举i,j(i,j为x)
再枚举k(k为y)
统计有多少个余数,加起来就好

#include<iostream>#include<cstdio>#include<cstring>using namespace std;const int maxn = 400 + 100;int a[maxn][maxn], sum[maxn][maxn],cnt[1000010],b[1000010];int n,m,k;long long ans = 0;int read() {    int x = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1;        ch = getchar();    }    while(ch >= '0' && ch <= '9') {        x = (x << 1) + (x << 3) + ch -'0';        ch =getchar();    }    return x * f;}int main() {    n = read(), m = read(), k = read();    for(int i = 1; i <= n; i++) {        for(int j = 1; j <= m; j++) {            a[i][j] = read();            sum[i][j] = (sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + a[i][j]) % k;        }    }    for(int i = 0; i < n; i++) {        for(int j = i + 1; j <= n; j++) {            cnt[0] = 1;            for(int t = 1; t <= m; t++) {                b[t] = (sum[j][t] - sum[i][t]) % k;                if(b[t] < 0) b[t] += k;                ans += cnt[b[t]];                cnt[b[t]]++;            }            for(int t = 1; t <= m; t++) cnt[b[t]] = 0;        }    }    cout<<ans<<endl;    return 0;}

历史/落在/赢家/之手
至少/我们/拥有/传说
谁说/败者/无法/不朽
拳头/只能/让人/低头
念头/却能/让人/抬头
抬头/去看/去爱/去追
你心中的梦
题目描述

又想起了四月。

如果不是省选,大家大概不会这么轻易地分道扬镳吧? 只见一个又一个昔日的队友离开了机房。

凭君莫话封侯事,一将功成万骨枯。

梦里,小 F 成了一个给将军送密信的信使。

现在,有两封关乎国家生死的密信需要送到前线大将军帐下,路途凶险,时间紧迫。小 F 不因为自己的祸福而避趋之,勇敢地承担了这个任务。

不过,小 F 实在是太粗心了,他一不小心把两封密信中的一封给弄掉了。

小 F 偷偷打开了剩下的那封密信。他 发现一副十分详细的地图,以及几句批文——原来 这是战场周围的情报地图。他仔细看后发现,在这张地图上标记了 n 个从 1 到 n 标号的 驿站,n − 1 条长度为 1 里的小道,每条小道双向连接两个不同的驿站,并且驿站之间可以 通过小道两两可达。

小 F 仔细辨认着上面的批注,突然明白了丢失的信的内容了。原来,每个驿站都可以驻 扎一个小队,每个小队可以控制距离不超过 k 里的驿站。如果有驿站没被控制,就容易产 生危险——因此这种情况应该完全避免。而那封丢失的密信里,就装着朝廷数学重臣留下的 精妙的排布方案,也就是用了最少的小队来控制所有驿站。

小 F 知道,如果能计算出最优方案的话,也许他就能够将功赎过,免于死罪。他找到了 你,你能帮帮他吗? 当然,小 F 在等待你的支援的过程中,也许已经从图上观察出了一些可能会比较有用的 性质,他会通过一种特殊的方式告诉你。

输入输出格式

输入格式:
从标准输入中读入数据。

输入第 1 行一个正整数 n,k,t,代表驿站数,一支小队能够控制的最远距离,以及特 殊性质所代表的编号。关于特殊性质请参照数据范围。

输入第 2 行至第 n 行,每行两个正整数 u ,v,表示在 u和 v 间,有一条长度为 一里的小道。

输出格式:
输出到标准输出中。

输出一行,为最优方案下需要的小队数。

输入输出样例

输入样例#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

n <= 1e5,. k <= 20

//贪心想错了,以为是按照每个点的入度数来做

正解是
按照点的深度排序(BFS序的倒序也可以),爆搜即可

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;const int maxn = 100000 + 100;int n,k,t;struct edge {    int u,v,next;}e[maxn<<1];int head[maxn], tot = 0;int sum = 0, vis[maxn];void add(int u, int v) {    e[++tot] = (edge){u,v,head[u]};    head[u] = tot;}int read() {    int x = 0, f = 1;    char ch = getchar();    while(ch < '0' || ch > '9') {        if(ch == '-') f = -1;        ch = getchar();    }    while(ch >= '0' && ch <= '9') {        x = (x << 1) + (x << 3) + ch -'0';        ch =getchar();    }    return x * f;}int fa[maxn],dep[maxn],val[maxn];void dfs(int x, int f) {    for(int i = head[x]; i; i = e[i].next) {        int v = e[i].v;        if(v != f) {            fa[v] = x;            dep[v] = dep[x] + 1;            val[v] = v;            dfs(v,x);        }    }}bool cmp(int a, int b) {    return dep[a] > dep[b];}int ans = 0;void dfs_(int x,int f,int d) {    vis[x] = 1;    if(!d) return;    for(int i = head[x]; i; i = e[i].next) {        int v = e[i].v;        if(v != f) {            dfs_(v,x,d - 1);        }    }}int main() {    //freopen("in.txt","r",stdin);    n = read(), k = read(), t = read();    for(int i = 1; i < n; i++) {        int u = read(), v = read();        add(u,v),add(v,u);    }    if(k == 0) {        cout<<n<<endl;        return 0;    }    fa[1] = 1;    dep[1] = 1;    val[1] = 1;    dfs(1,1);    sort(val + 1, val + 1 + n,cmp);    for(int i = 1; i <= n; i++) {        int v = val[i];        if(!vis[v]) {            for(int j = 1; j <= k; j++) v = fa[v];            dfs_(v,0,k);sum++;        }    }    cout<<sum<<endl;    return 0;}

//T3随机数8分
正解是状压DP(去年刚考了,今年应该不会考吧,不改了)

原创粉丝点击