A- Roads not only in Berland
题目大意:给你N个点和N-1条边,每次操作要隐藏一条边和增加一条边,问最少第几次操作时N个城市可以互相到达
可以考虑并查集合并时判断环,答案就是环的个数。判断到环时记录环上一条边为隐藏边,要添加的边就是根结点与根节点直接的边。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
int fa[maxn],r[maxn],l[maxn],t[maxn];
int find(int x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)fa[i]=i;
int x,y,cnt=0,ans=0;
for(int i=1;i<n;i++)
{
cin>>x>>y;
int fx=find(x);
int fy=find(y);
if(fx==fy)
{
cnt++;
l[cnt]=x;
r[cnt]=y;
}
else fa[fx]=fy;
}
for(int i=1;i<=n;i++)
{
if(find(i)==i)ans++,t[ans]=i;
}
printf("%d\n",cnt);
for(int i=1;i<=cnt;i++)
{
printf("%d %d %d %d\n",l[i],r[i],t[i],t[i+1]);
}
return 0;
}
B-Unordered Subsequence
签到题,找最小不规则子序列。可看出 有解时最小必定是3.
#include <bits/stdc++.h>
using namespace std;
long long n, a[100010], m = 0;
int main()
{
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
for (int i = 0; i < n - 1; i++)
if ((a[i] - a[0]) * (a[i + 1] - a[i]) < 0)
{
cout << 3 << endl
<< 1 << " " << i + 1 << " " << i + 2 << endl;
return 0;
}
cout << 0;
}
C-Wooden Fence
题目大意:一个人要修建篱笆,找了一家木篱笆公司买木板。这个公司若干种类的木板,并且仓库足够大,所以每种种类的木板数量可以看做无限大。现在这个人从这个公司买回若干种类的木板若干块。一块木板的种类由它的长和宽决定。不同的长宽表示不同的木板种类。现在这个人想尽可能构建出漂亮的篱笆,漂亮的篱笆,有两个条件
1 不允许有连续两个以上的相同种类的木板
2 下一块模板的长度要等于上一块木板的宽度
木板可以旋转,长宽互换。现在给出木板的种类数目(块数)和要构建篱笆的长度。问有多少种排列方式可以构建出漂亮的篱笆。最后的答案非常大,需要mod 1e9+7。
输入的N代表的是木板的种类,这两块木板出现在下面的输入数据中,说明这两块木板应该看做不同种类的木板,只有一块木板旋转以后才看做相同的木板。然后就可以用DP做了。构建一个DP数组【i】【j】代表当前已经构建了长度为i的篱笆,最后一块木板是j的方案总数。开始dp数组清零。开始的时候处理每一块木板,然后对应的木板加1;然后开始循环。
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e3+110;
const int mod=1e9+7;
int dp[maxn][310];
int a[310],b[310];
int main()
{
int l,n,x,y,ans=0;
cin>>n>>l;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i];
dp[a[i]][i]++;
if(a[i]!=b[i])
{
a[i+n]=b[i];
b[i+n]=a[i];
dp[a[i+n]][i+n]++;
}
}
for(int i=1;i<=l;i++)
{
for(int j=1;j<=n*2;j++)
{
if(!dp[i][j])continue;
for(int k=1;k<=n*2;k++)
{
if((j%n)!=(k%n) && b[j]==a[k])dp[i+a[k]][k]=(dp[i+a[k]][k]+dp[i][j])%mod;
}
}
}
for(int i=1;i<=2*n;i++)ans=(ans+dp[l][i])%mod;
cout<<ans<<endl;
return 0;
}
D-Headquarters
假签到 画画图找规律,找到真签到
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
long long a = 1, b = 1;
string s;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> s;
if (s == "UL" || s == "DR")
a++;
else if (s == "UR" || s == "DL")
b++;
else
a++, b++;
}
cout << a * b << endl;
return 0;
}
E-Zoo
题意:有n个望远镜,被放置在X轴1~n的位置上,现有m只鸟,望远镜可以以任何角度观察,能看到在那条直线上的所有鸟,
问所有望远镜能看到的鸟的数量之和
计算几何+暴力
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 10;
typedef long long int ll;
int n, m;
int num[maxn];
struct line
ll a,
b, c;
}
;
struct point
{
ll x, y;
} niao[300];
line ppline(point p1, point p2)
{
line l;
l.a = p2.y - p1.y;
l.b = p1.x - p2.x;
l.c = p1.y * p2.x - p1.x * p2.y;
return l;
}
int online(point p, line l)
{
if (p.x * l.a + p.y * l.b + l.c == 0)
return 1;
return 0;
}
int xofline(int y, line l)
{
if (l.a == 0)
return -1;
if (l.c % l.a != 0)
return -1;
double ret;
ret = -(l.c * 1.0 / l.a);
if (ret > 1000099 || ret < 0)
return -1;
return -l.c / l.a;
}
int main()
{
int i, j, k, ret;
scanf("%d%d", &n, &m);
memset(num, 0, sizeof(num));
for (i = 1; i <= m; ++i)
scanf("%lld%lld", &niao[i].x, &niao[i].y);
for (i = 1; i <= m; i++)
{
for (j = i + 1; j <= m; j++)
{
line l = ppline(niao[i], niao[j]);
int you = 2;
for (k = j + 1; k <= m; ++k)
{
if (online(niao[k], l))
you++;
}
int x = xofline(0, l);
if (x >= 1 && x <= n && num[x] < you)
num[x] = you;
}
}
ret = 0;
for (i = 1; i <= n; ++i)
if (num[i])
ret += num[i];
else
ret += 1;
printf("%d\n", ret);
return 0;
}
F-
题目大意:n个点,m辆车,r轮比赛,两点之间使用不同的车消耗不同的时间,每轮比赛给出a,b,c表示从a走到b最多允许转换c次车,问每轮比赛的最短时间
(1)以允许转换车的次数进行dp,dp[i][j][k]表示做多允许转换i次车,从j走到k所需的最短时间; dp[i][j][k]=min(dp[i-1][j][h]+dp[0][h][k]);
(2)在一条路径上最多转换n-1次车;
#include<bits/stdc++.h>
using namespace std;
const int maxn=70;
int cost[maxn][maxn][maxn],dp[maxn*20][maxn][maxn];
const int inf=0x3f3f3f3f;
int main()
{
int n,r,x,y,k,m;
scanf("%d%d%d",&n,&m,&r);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
for(k=1;k<=n;k++)scanf("%d",&cost[i][j][k]);
for(k=1;k<=n;k++)
for(x=1;x<=n;x++)
for(y=1;y<=n;y++)cost[i][x][y]=min(cost[i][x][y],cost[i][x][k]+cost[i][k][y]);
}
for(int i=0;i<=1001;i++)
for(int j=1;j<=n;j++)
for(k=1;k<=n;k++)dp[i][j][k]=inf;
for(int i=1;i<=m;i++)
for(k=1;k<=n;k++)
for(x=1;x<=n;x++)
for(y=1;y<=n;y++)
dp[0][x][y]=min(dp[0][x][y],cost[i][x][k]+cost[i][k][y]);
for(int i=1;i<n;i++)
for(k=1;k<=n;k++)
for(x=1;x<=n;x++)
for(y=1;y<=n;y++)
dp[i][x][y]=min(dp[i][x][y],dp[i-1][x][k]+dp[0][k][y]);
for(int i=1;i<=r;i++)
{
scanf("%d%d%d",&x,&y,&k);
int ans=inf;
k=min(n,k);
for(int i=0;i<=k;i++)ans=min(ans,dp[i][x][y]);
printf("%d\n",ans);
}
return 0;
}
G-Non-Secret Cypher
题目大意:给出n个元素的数列(n<=4e5),问有多少个子区间满足至少有一个数值出现至少K次。
就是先找到一个符合条件的区间[l,r]记为尺子,然后用哈希记录下该区间各个值的情况,然后将尺子右移,对尺子两端的数据进行增减,判断是否满足k,不满足尺子右端伸长到满足为止,对于每一次符合条件的情况,答案ans应该加上n-r,累加下来就是答案
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
int main()
{
ll ans=0,r=0;
map<ll,ll> pre;
map<ll,ll> next;
map<ll,ll> lma;
map<ll,ll> mp;
int n,a,k;
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
mp[a]++;
if(pre[a]!=0)next[pre[a]]=i;
pre[a]=i;
if(lma[a]==0)lma[a]=i;
if(mp[a]==k)
{
r=max(r,lma[a]);
}
if(mp[a]>k)
{
lma[a]=next[lma[a]];
r=max(r,lma[a]);
}
ans+=r;
}
printf("%lld\n",ans);
return 0;
}
H-Two Paths
去掉一条边 剩下的2棵树的直径 乘积 求最大
列举每条边 2次bfs求直径 其实总共是 4*(n-1) 次bfs
#include<bits/stdc++.h>
using namespace std;
const int maxn=210;
int dis[maxn];
struct node
{
int x,y;
}e[maxn];
bool mp[maxn][maxn];
int n;
int bfs(int u)
{
memset(dis,0,sizeof(dis));
dis[u]=1;
queue<int> q;
q.push(u);
while(!q.empty())
{
u=q.front();
q.pop();
for(int i=1;i<=n;i++)
{
if(mp[u][i] && !dis[i])
{
dis[i]=dis[u]+1;
q.push(i);
}
}
}
int tmp=0;
for(int i=1;i<=n;i++)if(dis[tmp]<dis[i])tmp=i;
memset(dis,0,sizeof(dis));
dis[tmp]=1;
q.push(tmp);
while(!q.empty())
{
u=q.front();
q.pop();
for(int i=1;i<=n;i++)
{
if(mp[u][i] && !dis[i])
{
dis[i]=dis[u]+1;
q.push(i);
}
}
}
tmp=0;
for(int i=1;i<=n;i++)tmp=max(tmp,dis[i]);
return tmp-1;
}
int main()
{
int ans=0;
cin>>n;
for(int i=1;i<n;i++)
{
cin>>e[i].x>>e[i].y;
mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=true;
}
for(int i=1;i<n;i++)
{
mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=false;
int l1=bfs(e[i].x);
int l2=bfs(e[i].y);
ans=max(ans,l1*l2);
mp[e[i].x][e[i].y]=mp[e[i].y][e[i].x]=true;
}
cout<<ans<<endl;
return 0;
}