比赛题目:
http://acm.hdu.edu.cn/downloads/CCPC2018-Hangzhou-ProblemSet.pdf
A.
HDU’s n classrooms are on a line ,which can be considered as a number line. Each classroom has a coordinate. Now Little Q wants to build several candy shops in these n classrooms.
The total cost consists of two parts. Building a candy shop at classroom i would have some cost ci. For every classroom P without any candy shop, then the distance between P and the rightmost classroom with a candy shop on P's left side would be included in the cost too. Obviously, if there is a classroom without any candy shop, there must be a candy shop on its left side.Now Little Q wants to know how to build the candy shops with the minimal cost. Please write a program to help him.
Input
The input contains several test cases, no more than 10 test cases.
In each test case, the first line contains an integer n(1≤n≤3000), denoting the number of the classrooms.
In the following n lines, each line contains two integers xi,ci(−109≤xi,ci≤109), denoting the coordinate of the i-th classroom and the cost of building a candy shop in it.
There are no two classrooms having same coordinate.
Output
For each test case, print a single line containing an integer, denoting the minimal cost.
Sample Input
3
1 2
2 3
3 4
4
1 7
3 1
5 10
6 1
Sample Output
5
11
题目大意:就是给了每个点的坐标和在该点建房子的花费。如果不建房子那么花费是跟与往左边找离他最近的一个房子的距离有关的,距离之和。求最小花费是多少。
dp题。预处理一下各个点之间的距离。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=1000000010;
const long long inf=1e18;
long long jvli[3005][3005];//标记教学楼之间的距离
struct node
{
int pos,cost;
}lala[3005];
long long dp[3005][2];
bool cmp(node x,node y)
{
return x.pos<y.pos;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%d%d",&lala[i].pos,&lala[i].cost);
}
sort(lala+1,lala+1+n,cmp);
for(int i=1;i<=n;i++)
{
jvli[i][i]=0;
for(int j=i+1;j<=n;j++)
{
jvli[i][j]=lala[j].pos-lala[i].pos+jvli[i][j-1];
}
}
/*
for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
cout<<i<<" -> "<<j<<" :"<<jvli[i][j]<<endl;
}
}
*/
for(int i=1;i<=n;i++)
{
dp[i][0]=dp[i][1]=inf;
}
dp[1][1]=lala[1].cost;
for(int i=2;i<=n;i++)
{
dp[i][1]=min(dp[i-1][0],dp[i-1][1])+lala[i].cost;
for(int j=i-1;j>=1;j--)
{
dp[i][0]=min(dp[j][1]+jvli[j][i],dp[i][0]);
}
}
cout<<min(dp[n][0],dp[n][1])<<endl;
}
return 0;
}
B:
Do you know what is called ``Coprime Sequence''? That is a sequence consists of n positive integers, and the GCD (Greatest Common Divisor) of them is equal to 1.
``Coprime Sequence'' is easy to find because of its restriction. But we can try to maximize the GCD of these integers by removing exactly one integer. Now given a sequence, please maximize the GCD of its elements.
Input
The first line of the input contains an integer T(1≤T≤10), denoting the number of test cases.
In each test case, there is an integer n(3≤n≤100000) in the first line, denoting the number of integers in the sequence.
Then the following line consists of n integers a1,a2,...,an(1≤ai≤109), denoting the elements in the sequence.
Output
For each test case, print a single line containing a single integer, denoting the maximum GCD.
Sample Input
3
3
1 1 1
5
2 2 2 3 2
4
1 2 4 8
Sample Output
1
2
2
题意就是剔除掉一个点,使得gcd最大。
思路:求前缀gcd,再求后缀gcd,然后遍历一遍,找出最大gcd.
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+300;
int pre[maxn],suf[maxn];
int arr[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&arr[i]);
}
int flag = arr[0];
for(int i=1;i<n;i++)
{
pre[i]=flag;//求前缀gcd
flag = __gcd(flag,arr[i]);
}
flag = arr[n-1];
for(int i=n-2;i>=0;i--)
{
suf[i]=flag//求后缀gcd
flag=__gcd(flag,arr[i]);
}
int res=max(suf[0],pre[n-1]);
for(int i=1;i<n-1;i++)//遍历
{
res = max(res,__gcd(pre[i],suf[i]));
}
printf("%d\n",res);
}
}
C:Little Q is crazy about graph theory, and now he creates a game about graphs and trees.
There is a bi-directional graph with n nodes, labeled from 0 to n−1. Every edge has its length, which is a positive integer ranged from 1 to 9.
Now, Little Q wants to delete some edges (or delete nothing) in the graph to get a new graph, which satisfies the following requirements:
(1) The new graph is a tree with n−1 edges.
(2) For every vertice v(0<v<n), the distance between 0 and v on the tree is equal to the length of shortest path from 0 to v in the original graph.
Little Q wonders the number of ways to delete edges to get such a satisfied graph. If there exists an edge between two nodes i and j, while in another graph there isn't such edge, then we regard the two graphs different.
Since the answer may be very large, please print the answer modulo 109+7.
Input
The input contains several test cases, no more than 10 test cases.
In each test case, the first line contains an integer n(1≤n≤50), denoting the number of nodes in the graph.
In the following n lines, every line contains a string with n characters. These strings describes the adjacency matrix of the graph. Suppose the j-th number of the i-th line is c(0≤c≤9), if c is a positive integer, there is an edge between i and j with length of c, if c=0, then there isn't any edge between i and j.
The input data ensure that the i-th number of the i-th line is always 0, and the j-th number of the i-th line is always equal to the i-th number of the j-th line.
Output
For each test case, print a single line containing a single integer, denoting the answer modulo 109+7.
Sample Input
2
01
10
4
0123
1012
2101
3210
Sample Output
1
6
题目大意:给定有向图。0节点到每个节点都有一个最短距离。问有几种删边的方法可以使得0到其他点的最短距离依旧不变。
思路:就是找到这个点有几种方法可以到达。每个节点的种类数相乘(其实我想了好久也不知道为什么这样成立。,,是学长的思想)
代码就比较简单了,由于点比较小,用floyd居然也能过。
代码:
#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
const int INF=100000000;
int n;
int a[100][100];
int num[100];
int d[100][100];
void floyd()
{
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(d[i][k]+d[k][j]<d[i][j])
d[i][j]=d[i][k]+d[k][j];
}
}
}
}
int main()
{
char ch;
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cin>>ch;
a[i][j]=ch-'0';
if(a[i][j]==0&&i!=j)
d[i][j]=INF;
else
d[i][j]=a[i][j];
}
}
floyd();
long long sum=1;
memset(num,0,sizeof(num));
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(i==j)
continue;
else if(a[i][j]==0)
continue;
else
{
if(d[1][i]+a[i][j]==d[1][j])
num[j]++;
}
}
}
for(int i=1;i<=n;i++)
{
if(num[i]!=0)
sum=sum*num[i]%mod;
//cout<<num[i]<<" *** "<<endl;
}
cout<<sum%mod<<endl;
}
return 0;
}
D:水题就不写了
E:还没搞懂题,待补
F:Little Q loves playing with different kinds of graphs very much. One day he thought about an interesting category of graphs called ``Cool Graph'', which are generated in the following way:
Let the set of vertices be {1, 2, 3, ..., n}. You have to consider every vertice from left to right (i.e. from vertice 2 to n). At vertice i, you must make one of the following two decisions:
(1) Add edges between this vertex and all the previous vertices (i.e. from vertex 1 to i−1).
(2) Not add any edge between this vertex and any of the previous vertices.
In the mathematical discipline of graph theory, a matching in a graph is a set of edges without common vertices. A perfect matching is a matching that each vertice is covered by an edge in the set.
Now Little Q is interested in checking whether a ''Cool Graph'' has perfect matching. Please write a program to help him.
Input
The first line of the input contains an integer T(1≤T≤50), denoting the number of test cases.
In each test case, there is an integer n(2≤n≤100000) in the first line, denoting the number of vertices of the graph.
The following line contains n−1 integers a2,a3,...,an(1≤ai≤2), denoting the decision on each vertice.
Output
For each test case, output a string in the first line. If the graph has perfect matching, output ''Yes'', otherwise output ''No''.
Sample Input
3
2
1
2
2
4
1 1 2
Sample Output
Yes
No
No
题目大意:就是能否有这种情况,使得子集是完美匹配。(比赛时思维好差,学长一眼就有了思路。)
代码1:
#include<bits/stdc++.h>
using namespace std;
const int maxn=100000+300;
bool vis[maxn];
int main(){
int t;
scanf("%d",&t);
while(t--){
memset(vis,0,sizeof(vis));
int n;
scanf("%d",&n);
int l=0,r=1;
int m=0;
for(int i=1;i<n;i++){
scanf("%d",&m);
if(m==1){
while(vis[l]!=false && l<r){
l++;
}
if(l!=r) {
vis[r]=vis[l]=true;
}
}
r++;
}
while(vis[l]!=false && l<r) l++;
if(l==r) printf("Yes\n");
else printf("No\n");
}
}
代码2:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
int a[100010];
int logal=0;
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
logal=0;
for(int i=2;i<=n;i++)
{
cin>>a[i];
}
if(n%2==0)
{
int sum=0;
for(int i=n;i>=2;i--)
{
if(a[i]==1)
sum++;
else if(a[i]==2)
{
sum--;
}
if(sum<0)
{
logal=1;
cout<<"No"<<endl;
break;
}
}
if(logal==0)
{
cout<<"Yes"<<endl;
}
}
else
cout<<"No"<<endl;
}
return 0;
}
G:G题就是一个递推dp[i]=dp[i-1]+dp[i-3]
由于比较大,所以要用到矩阵快速幂。还没看,以后补上。
H:LCA加上二分
I:没看
J:一道模拟题
MG is a rich boy. He has n apples, each has a value of V(0<=V<=9).
A valid number does not contain a leading zero, and these apples have just made a valid N digit number.
MG has the right to take away K apples in the sequence, he wonders if there exists a solution: After exactly taking away K apples, the valid N−K digit number of remaining apples mod 3 is zero.
MG thought it very easy and he had himself disdained to take the job. As a bystander, could you please help settle the problem and calculate the answer?
Input
The first line is an integer T which indicates the case number.(1<=T<=60)
And as for each case, there are 2 integer N(1<=N<=100000),K(0<=K<N) in the first line which indicate apple-number, and the number of apple you should take away.
MG also promises the sum of N will not exceed 1000000。
Then there are N integers X in the next line, the i-th integer means the i-th gold’s value(0<=X<=9).
Output
As for each case, you need to output a single line.
If the solution exists, print”yes”,else print “no”.(Excluding quotation marks)
Sample Input
2
5 2
11230
4 2
1000
Sample Output
yes
no
ps:感谢学长大佬们带我飞的这几天~