Gargari is jealous that his friend Caisa won the game from the previous problem. He wants to prove that he is a genius.
He has a n × n chessboard. Each cell of the chessboard has a number written on it. Gargari wants to place two bishops on the chessboard in such a way that there is no cell that is attacked by both of them. Consider a cell with number x written on it, if this cell is attacked by one of the bishops Gargari will get x dollars for it. Tell Gargari, how to place bishops on the chessboard to get maximum amount of money.
We assume a cell is attacked by a bishop, if the cell is located on the same diagonal with the bishop (the cell, where the bishop is, also considered attacked by it).
The first line contains a single integer n (2 ≤ n ≤ 2000). Each of the next n lines contains n integers aij (0 ≤ aij ≤ 109) — description of the chessboard.
On the first line print the maximal number of dollars Gargari will get. On the next line print four integers: x1, y1, x2, y2 (1 ≤ x1, y1, x2, y2 ≤ n), where xi is the number of the row where the i-th bishop should be placed, yi is the number of the column where the i-th bishop should be placed. Consider rows are numbered from 1 to n from top to bottom, and columns are numbered from 1 to n from left to right.
If there are several optimal solutions, you can print any of them.
4 1 1 1 1 2 1 1 0 1 1 1 0 1 0 0 1
12 2 2 3 2
思路:首先与处理处所有的对角线的元素和,然后暴力就行了,因为要求两个像不能有重叠,所以只需要枚举奇偶不同的就行了
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=2020;
typedef long long LL;
LL sum[2][maxn*2];
pair<int,int> ans[2];
int a[maxn][maxn],n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)sum[0][i-j+n]+=a[i][j],sum[1][i+j]+=a[i][j];
LL first=0,two=0;
ans[0]=make_pair(1,1),ans[1]=make_pair(1,2);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
LL tmp=sum[0][i-j+n]+sum[1][i+j]-a[i][j];
if((i+j)&1)
{
if(tmp>first)
ans[0]=make_pair(i,j),first=tmp;
}
else if(tmp>two)
ans[1]=make_pair(i,j),two=tmp;
}
}
cout<<first+two<<endl;
cout<<ans[0].first<<" "<<ans[0].second<<" "<<ans[1].first<<" "<<ans[1].second<<endl;
return 0;
}
Gargari got bored to play with the bishops and now, after solving the problem about them, he is trying to do math homework. In a math book he have found k permutations. Each of them consists of numbers 1, 2, ..., n in some order. Now he should find the length of the longest common subsequence of these permutations. Can you help Gargari?
You can read about longest common subsequence there: https://en.wikipedia.org/wiki/Longest_common_subsequence_problem
The first line contains two integers n and k (1 ≤ n ≤ 1000; 2 ≤ k ≤ 5). Each of the next k lines contains integers 1, 2, ..., n in some order — description of the current permutation.
Print the length of the longest common subsequence.
4 3 1 4 2 3 4 1 2 3 1 2 4 3
3
The answer for the first test sample is subsequence [1, 2, 3].
思路:以前在训练指南上做过一个类似的,是吧LCS转换成LIS,但那个是两个序列,这里是k个,首先根据第一个序列对2~k重新编号,然后根据第二个对3~k重新编号,以此类推,最后就是求最后一个序列的最长上升子序列,要注意这里要保证1~k-1也是上升的
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxn=1010;
const int INF=1000000000;
int num[maxn],g[maxn],d[maxn];
int a[6][maxn];
int n,k;
bool check(int x,int y)
{
for(int i=k;i>1;i--)
if(a[i][x]>a[i][y])
{
x=a[i][x];
y=a[i][y];
}
else return false;
return true;
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=k;i++)
for(int j=1;j<=n;j++)scanf("%d",&a[i][j]);
for(int i=1;i<k;i++)
{
for(int j=1;j<=n;j++)num[a[i][j]]=j;
for(int j=i+1;j<=k;j++)
for(int p=1;p<=n;p++)a[j][p]=num[a[j][p]];
}
for(int i=1;i<=n;i++)g[i]=INF;
int ans=0;
for(int i=1;i<=n;i++)
for(int j=0;j<i;j++)
if(check(i,j)||j==0)
d[i]=max(d[i],d[j]+1);
for(int i=1;i<=n;i++)ans=max(ans,d[i]);
cout<<ans<<endl;
return 0;
}
Caisa is now at home and his son has a simple task for him.
Given a rooted tree with n vertices, numbered from 1 to n (vertex 1 is the root). Each vertex of the tree has a value. You should answer q queries. Each query is one of the following:
- Format of the query is "1 v". Let's write out the sequence of vertices along the path from the root to vertex v: u1, u2, ..., uk (u1 = 1; uk = v). You need to output such a vertex ui that gcd(value of ui, value of v) > 1 and i < k. If there are several possible vertices ui pick the one with maximum value of i. If there is no such vertex output -1.
- Format of the query is "2 v w". You must change the value of vertex v to w.
You are given all the queries, help Caisa to solve the problem.
The first line contains two space-separated integers n, q (1 ≤ n, q ≤ 105).
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 2·106), where ai represent the value of node i.
Each of the next n - 1 lines contains two integers xi and yi (1 ≤ xi, yi ≤ n; xi ≠ yi), denoting the edge of the tree between vertices xi and yi.
Each of the next q lines contains a query in the format that is given above. For each query the following inequalities hold: 1 ≤ v ≤ n and 1 ≤ w ≤ 2·106. Note that: there are no more than 50 queries that changes the value of a vertex.
For each query of the first type output the result of the query.
4 6 10 8 4 3 1 2 2 3 3 4 1 1 1 2 1 3 1 4 2 1 9 1 4
-1 1 2 -1 1
gcd(x, y) is greatest common divisor of two integers x and y.
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
const int maxm=2000010;
const int maxn=100010;
int prime[2010],vis[2010];
int val[maxn],l[maxn],r[maxn],ans[maxn],dep[maxn];
int n,q,num,cnt;
vector<int> h[maxm];
vector<int> g[maxn];
void get_prime()
{
num=0;
vis[0]=vis[1]=1;
for(int i=2;i<2001;i++)
{
if(!vis[i])
{
prime[num++]=i;
}
for(int j=0;j<num;j++)
{
if(i*prime[j]>=2001)break;
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
void add(int x,int y)
{
h[x].push_back(y);
}
int find(int x)
{
if(h[x].size())return h[x][h[x].size()-1];
return 0;
}
void del(int x)
{
if(h[x].size())h[x].pop_back();
}
void dfs(int u,int pos,int all,int flag,int fa)
{
ans[u]=0;
int tmp=val[u];
for(int i=0;i<num&&prime[i]*prime[i]<=tmp;i++)
{
if(tmp%prime[i]==0)
{
int v=find(prime[i]);
if(dep[ans[u]]<dep[v])ans[u]=v;
add(prime[i],u);
while(tmp%prime[i]==0)tmp/=prime[i];
}
}
if(tmp>1)
{
int v=find(tmp);
if(dep[ans[u]]<dep[v])ans[u]=v;
add(tmp,u);
}
if(!flag)l[u]=++cnt;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v==fa)continue;
if(!flag)dep[v]=dep[u]+1;
//if(all||flag==u||l[v]<=pos&&pos<=r[v])加上这句话跑400ms,不加跑3000ms,但是没太懂什么意思
dfs(v,pos,all||flag==u,flag,u);
}
if(!flag)r[u]=cnt;
tmp=val[u];
for(int i=0;i<num&&prime[i]*prime[i]<=tmp;i++)
{
if(tmp%prime[i]==0)
{
del(prime[i]);
while(tmp%prime[i]==0)tmp/=prime[i];
}
}
if(tmp>1)
del(tmp);
}
int main()
{
get_prime();
dep[1]=1;
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%d",&val[i]);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
g[x].push_back(y);
g[y].push_back(x);
}
dfs(1,1,1,0,1);
while(q--)
{
int op,u,v;
scanf("%d",&op);
if(op==1)
{
scanf("%d",&v);
cout<<(ans[v]?ans[v]:-1)<<endl;
}
else
{
scanf("%d%d",&u,&v);
val[u]=v;
dfs(1,l[u],0,u,1);
}
}
return 0;
}