总结:
头天晚上饮酒过度,第二天昏昏沉沉的。还好队友比较给力,过了D题的后缀数组(说实话这个数据结构还是第一次听说)I题的计算几何(更偏向思维题的那种)和B题的数学题(矩阵快速幂)。
自己的话。上去过了A题水题,不过手速比较慢,1’14’27时候过的。是一个简单的图遍历,由于数据量不大DFS就能做,时候讨论的时候发现还可以用floyd。
最后慢慢熬,把H题熬了出来,不过只是说思路让队友敲,4’58’10。给一个n*n矩阵,n为100大小,每个格子上有一个数值。问从第1*1个格子走到n*n个格子,把经过的格子的数值乘起来,得到的数尾0的个数最少多少个。初步思路求出每个格子的2和5的个数,做出D题的队友说可以分别统计2最少和5最少的情况。想啊想,决定用BFS的做法,一个斜线为一层往下遍历(y-x为定值)。每次遇到一个格子的值比预定值要小时,就用它更新左边和上边的点(上一层相邻的点),然后一直更新下去知道重新回到这条斜线。
赛中的时候E题一直TLE,也没仔细看。赛后过了。首先每个数最多有20多个质因子,因此可以开一个vector来存每个质因子包含的下标是谁。
然而并不够,此题还有一个巨蛋疼的优化,就是初始化每个vector的时候需要进行剪枝。最终优化版本是穷举质因子直到质因子小于等于该数的开方。这时退出,若该数仍然大于1,则说明该数是一个质数,在该数的容器中压入该下标。这样省了很多冗余步骤,不过这个小优化你竟然要T我也是很愤怒的。。。新学函数lower_bound(num,num+cnt,data)。在num数组的0到cnt-1的范围中寻找第一个大于等于data的位置,可用于二分查找(这个值-num可以得到它在num数组中的下标)。需要注意的是可能会返回cnt即在数组外,有时候有必要判断一下。
A:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
using namespace std;
#define gmax(a,b) a>b?a:b
#define gmin(a,b) a<b?a:b
const int MAXN = 100+5;
int dis[MAXN][MAXN];
queue<int>q1,q2;
int use[MAXN];
int n,m;
int val[MAXN];
int ans;
void bfs(int now)
{
use[now] = 1;
q1.push(now);
q2.push(0);
while(!q1.empty()){
int step = q2.front();q2.pop();
int mark = q1.front();q1.pop();
for(int i=1; i<=n; i++){
if(use[i] == 0 && dis[i][mark] == 1){
use[i] = 1;
q2.push(step+1);
q1.push(i);
}
}
ans = gmax(ans, step);
}
// if(ff == 1)
// ans = gmax(ans, step);
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
memset(dis, 0, sizeof(dis));
memset(use, 0, sizeof(use));
int le,ri;
for(int i=0; i<m; i++){
scanf("%d%d",&le, &ri);
dis[le][ri] = dis[ri][le] = 1;
}
for(int i=1; i<=n; i++){
ans = 0;
bfs(i);
memset(use, 0, sizeof(use));
val[i] = ans;
}
int mmin = 1000;
int cnt = 0;
for(int i=1; i<=n; i++){
if(val[i] == mmin)
cnt++;
else if(val[i] < mmin){
mmin = val[i];
cnt = 1;
}
}
// printf("val\n");
// for(int i=1; i<=n; i++)
// printf("%d ",val[i]);
// printf("\n");
printf("%d\n",cnt);
int ff = 1;
for(int i=1; i<=n; i++){
if(val[i] == mmin){
if(ff) ff = 0;
else printf(" ");
printf("%d",i);
}
}
printf("\n");
}
return 0;
}
/**************************************************************
Problem: 1659
User: ALPC_T4
Language: C++
Result: Accepted
Time:284 ms
Memory:1536 kb
****************************************************************/
H题:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
typedef struct
{
int x,y;
}QUE;
int dx[4] = {0,1,0,-1},dy[4] = {1,0,-1,0};
int num[1010][1010];
int n,rec[1010][1010],rrr[1010][1010];
bool visit[1010][1010],in[1010][1010];
QUE que[5000010];
int Work(int num,int p)
{
int cnt = 0;
while(num % p == 0)
{
cnt++;
num = num / p;
}
return cnt;
}
int BFS()
{
memset(visit,false,sizeof(visit));
memset(in,false,sizeof(in));
int x,y,nx,ny;
int head = 1,tail = 1;
que[1].x = 1; que[1].y =1;
in[1][1] = visit[1][1] = true;
rrr[1][1] = rec[1][1];
while(head <= tail)
{
x = que[head].x;
y = que[head].y;
head++;
in[x][y] = false;
for(int i = 0; i < 4; i++)
{
nx = x + dx[i];
ny = y + dy[i];
if(nx < 1 || nx > n) continue;
if(ny < 1 || ny > n) continue;
if(visit[nx][ny] == false)
{
tail++;
que[tail].x = nx;
que[tail].y = ny;
rrr[nx][ny] = rrr[x][y] + rec[nx][ny];
visit[nx][ny] = true;
in[nx][ny] = true;
}
else if(rrr[nx][ny] > rrr[x][y] + rec[nx][ny])
{
if(in[nx][ny] == false)
{
tail++;
que[tail].x = nx;
que[tail].y = ny;
in[nx][ny] = true;
}
rrr[nx][ny] = rrr[x][y] + rec[nx][ny];
}
}
}
return rrr[n][n];
}
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
scanf("%d",&num[i][j]);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
rec[i][j] = Work(num[i][j],2);
int ans_2 = BFS();
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
rec[i][j] = Work(num[i][j],5);
int ans_5 = BFS();
int ans = min(ans_2,ans_5);
printf("%d\n",ans);
}
/**************************************************************
Problem: 1657
User: ALPC_T4
Language: C++
Result: Accepted
Time:736 ms
Memory:54492 kb
****************************************************************/
E题:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
const int MAXN = 1e6+5;
int prime[MAXN],cnt;
int id[MAXN];
int vis[MAXN];
vector<int>dd[MAXN];
void init()
{
cnt = 0;
memset(vis, 0, sizeof(vis));
memset(id, -1, sizeof(id));
for(int i=2; i<MAXN; i++){
if(vis[i] == 0){
vis[i] = 1;
id[i] = cnt;
prime[cnt++] = i;
int now = i*2;
while(now < MAXN){
vis[now] = 1;
now += i;
}
}
}
}
int fi_vec(int mark, int now,int flag)
{
int le = 0;
int ri = dd[mark].size() - 1;
while(le < ri - 1){
int mid = (le + ri) / 2;
if(dd[mark][mid] < now)
le = mid;
else if(dd[mark][mid] > now)
ri = mid;
else if(dd[mark][mid] == now)
return mid;
}
if(dd[mark][le] >= now)
return le;
else if(dd[mark][ri] <= now)
return ri;
else if(flag == 0)
return ri;
else if(flag == 1)
return le;
}
int fi_prime(int pp)
{
int le = 0;
int ri = cnt - 1;
while(le < ri - 1){
int mid = (le + ri) / 2;
if(prime[mid] > pp)
ri = mid;
else if(prime[mid] < pp)
le = mid;
else if(prime[mid] == pp)
return mid;
}
if(prime[le] == pp)
return le;
return ri;
}
int main()
{
init();
// printf("max prime is = %d\n",prime[cnt-1]);
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
int temp;
for(int i=0; i<cnt; i++)
dd[i].clear();
for(int i=1; i<=n; i++){
scanf("%d",&temp);
// printf("first temp = %d\n",temp);
for(int j=0; prime[j]*prime[j]<= temp; j++){
if(temp % prime[j] == 0){
// printf("j = %d,id[j] = %d,temp = %d\n",j,id[j],temp);
dd[id[prime[j]]].push_back(i);
while(temp % prime[j] == 0)
temp /= prime[j];
}
// printf("temp = %d\n",temp);
// if(temp < j)
// break;
}
if(temp > 1)
dd[id[temp]].push_back(i);
}
// for(int i=0; i<cnt; i++)
// sort(dd[i].begin(), dd[i].end());
int le,ri,pp;
while(m--){
scanf("%d%d%d",&le,&ri,&pp);
int mark = id[pp];
// int mark = lower_bound(prime, prime+cnt, pp) - prime;
// printf("prime is %d,mark = %d\n",prime[mark],mark);
// printf("int the vector\n");
// for(int i=0; i<dd[mark].size(); i++)
// printf("%d ",dd[mark][i]);
// printf("\n");
if(dd[mark].size() == 0 || le > dd[mark][dd[mark].size()-1] || ri < dd[mark][0]){
printf("0\n");
continue;
}
// int st = lower_bound(dd[mark].begin(),dd[mark].end(),le) - dd[mark].begin();
// int re = lower_bound(dd[mark].begin(),dd[mark].end(),ri) - dd[mark].begin();
// if(re == dd[mark].size() || dd[mark][re] > ri)
// re--;
// printf("st = %d, re = %d\n",st,re);
int st = fi_vec(mark, le, 0);
int re = fi_vec(mark, ri, 1);
printf("%d\n",re - st + 1);
}
}
return 0;
}
B题(自己写赛后)
题目链接:
http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1658
题意:
给一个方程Y = (AX + BY)%P,X = Y。求n次运算后得到的Y值。
思路:
矩阵快速幂第一题。
源码:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <queue>
using namespace std;
typedef long long LL;
LL block[2][2];///存储矩阵
LL tblock[2][2];
LL x,y;
void mul1(LL p)
{
for(int i=0; i<2; i++){
for(int j=0; j<2; j++){
tblock[i][j] = 0;
for(int k=0; k<2; k++)
tblock[i][j] = (tblock[i][j] + block[i][k] * block[k][j]) % p;///1 1 = 10 * 0 1 + 11 * 11
}
}
for(int i=0; i<2; i++)
for(int j=0; j<2; j++)
block[i][j] = tblock[i][j];
}
void mul2(LL p)
{
LL ans = 0;
LL t1,t2;
// printf("before x = %lld, y = %lld\n",x,y);
// printf("block\n");
// for(int i=0; i<2; i++){
// for(int j=0; j<2; j++)
// printf("%lld ",block[i][j]);
// printf("\n");
// }
t2 = block[0][1] * x % p + block[1][1] * y % p;
t1 = block[0][0] * x % p + block[1][0] * y % p;
// printf("t1 = %lld, t2 = %lld\n",t1,t2);
x = t1 % p;
y = t2 % p;
// printf("after x = %lld, y = %lld\n",x,y);
}
int main()
{
int t;
scanf("%d",&t);
for(int cas = 1; cas <= t; cas++){
LL a,b,p,n;
scanf("%lld %lld %lld %lld %lld %lld",&x,&y,&a,&b,&p,&n);
// printf("n = %d\n",n);
block[0][0] = 0;
block[0][1] = a;
block[1][0] = 1;
block[1][1] = b;
LL ans = 0;
// printf("\nblock\n");
// for(int i=0; i<2; i++){
// for(int j=0; j<2; j++)
// printf("%d ",block[i][j]);
// printf("\n");
// }
while(n){
if(n & 1){
mul2(p);
}
mul1(p);
// printf("\nblock\n");
// for(int i=0; i<2; i++){
// for(int j=0; j<2; j++)
// printf("%d ",block[i][j]);
// printf("\n");
// }
// printf("n = %d\n",n);
n = n >> 1;
}
printf("Case #%d: %lld\n",cas,y);
}
return 0;
}
/*
0 1 * 0 1 = 1 1
1 1 1 1 1 2
*/