A-Tournament
签到题 瞎搞就行了
#include<bits/stdc++.h>
using namespace std;
int t[60],a[60];
int main()
{
int n,x,y;
cin>>n;
int cnt=n*(n-1)/2;
for(int i=1;i<cnt;i++)
{
cin>>x>>y;
t[x]++;
t[y]++;
a[x]++;
}
x=y=0;
for(int i=1;i<=n;i++)
{
if(t[i]!=(n-1))
{
if(x!=0)y=i;
else x=i;
}
}
if(a[x]>=a[y])cout<<x<<" "<<y;
else cout<<y<<" "<<x<<endl;
return 0;
}
B-pSort
题目大意:有一个n个数的序列初始值是1-n有序排列,给一个目标序列和每一位下标的值di,di的意义是|i-j|=di的数可交换即(i+di)(i-di)和i和交换。每一位可交换无数次,问能不能从初始序列交换成目标序列。
分析:可用并查集把所有能交换数归成一个集合,最后查目标序列i 和ai是不是都是一个集合的就行了
#include<bits/stdc++.h>
using namespace std;
int fa[110],a[110];
int find(int x)
{
if(x==fa[x])return x;
return fa[x]=find(fa[x]);
}
void cp(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
{
fa[fx]=fy;
}
}
int main()
{
int n,x;
cin>>n;
for(int i=1;i<=n;i++)
{
fa[i]=i;
cin>>a[i];
}
for(int i=1;i<=n;i++)
{
cin>>x;
int y=i+x;
if(y<=n)
{
cp(i,y);
}
y=i-x;
if(y>0)cp(i,y);
}
for(int i=1;i<=n;i++)
{
if(a[i]!=i)
{
if(find(i)!=find(a[i]))
{
puts("NO");
return 0;
}
}
}
puts("YES");
return 0;
}
c-Traffic Lights
签到题,注意题目中交代的红灯计算规则,想到2 1 1 1 1这个样例就可
#include<bits/stdc++.h>
using namespace std;
int main()
{
double l,d,v,g,r,ans;
cin>>l>>d>>v>>g>>r;
ans=l*1.0/v;
double tmp=d*1.0/v+0.000000000001,tot=g+r;
while(tmp>tot)tmp-=tot;
if(tmp >g)ans+=(r+g-tmp);
printf("%.8lf\n",ans);
return 0;
}
D-Volleyball
题目大意:城市里面有n个交叉路口,m条路,每条无向有长度,每个交叉路口都有一个出租车司机等待,出租车可以行使长度不超过ti的距离,花费为ci。告诉你起始路口,问到达目标路口的最小花费。
思路:求最小花费,可以转化为最短路问题。首先我们可以根据m条路对每个路口出租车司机可以到达的路口和花费建图,然后求新建图的最短路即可。建图时也需要用到最短路,要求出定距离可以到达最多的点。还有就是求最短路时初始值一定要足够大,因为wi是10^9.
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
struct node
{
int to,l,next;
}e[maxn*2];
struct bian{int l,u;};
const int inf=0x3f3f3f3f;
int head[maxn],vis[maxn];
long long int dis[maxn],t[maxn],c[maxn],mp[maxn][maxn];
int cnt,n,m,st,ed;
void add(int x,int y,int l)
{
e[cnt].l=l;
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
void bfs(int l,int cost,int u)
{
bian p,pp;
int s=u;
p.l=l,p.u=u;
queue<bian> q;
q.push(p);
while(!q.empty())
{
p=q.front();
q.pop();
u=p.u;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
pp.l=p.l-e[i].l;
if(pp.l>=0)
{
mp[s][v]=min(mp[s][v],(long long)cost);
if(!vis[v])
{
vis[v]=1;
pp.u=v;
q.push(pp);
}
}
}
}
}
long long int dij()
{
for(int i=1;i<=n;i++)
{
vis[i]=0;
dis[i]=1e15;
}
dis[st]=0;
for(int i=1;i<=n;i++)
{
int x=-1;
long long int tmp=1e15;
for(int j=1;j<=n;j++)
{
if(!vis[j] && dis[j]<tmp)
{
x=j;
tmp=dis[j];
}
}
//cout<<x<<endl;
if(x==-1)break;
vis[x]=1;
for(int j=1;j<=n;j++)
{
if(!vis[j])
{
dis[j]=min(dis[j],(long long)(dis[x]+mp[x][j]));
}
}
}
return dis[ed];
}
int main()
{
int x,y,l;
cin>>n>>m>>st>>ed;
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
cin>>x>>y>>l;
add(x,y,l);
add(y,x,l);
}
for(int i=1;i<=n;i++)
{
cin>>t[i]>>c[i];
for(int j=1;j<=n;j++)mp[i][j]=(1e15);
}
for(int i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
vis[i]=1;
bfs(t[i],c[i],i);
}
long long int ans=dij();
if(ans>=(1e15))puts("-1");
else cout<<ans<<endl;
return 0;
}
E-Name
题意:给你两个字符串s、t,输出由s组成的字符的一个排列,使得s字典序大于t,且字典序尽可能小
做法,贪心,要使字典序尽可能小又要大于t的字典序,则应该使得答案串与t串的前缀尽可能多的相同
然后就分两步走了
1 如果s中包含了t中的所有字符,且有多余的字符(因为字典序要严格大于t),则直接输出t,在接在后面输出剩下的字符的最小字典序的一个排列
2 假如1的条件不成立,就找这样一个位置,这个位置之前的字符都可以做到和t相同,且这个位置的字符要比t相应位置大,
因为要是前缀尽可能多的相同,所以贪心的从后往前求这个位置,找到这个位置后就可以把s中剩下的字符一并输出了
#include <bits/stdc++.h>
const int maxn = 5010;
char s[maxn];
char t[maxn];
int a[30], b[30];
int main()
{
int i, j, k, l;
bool can, flag;
scanf("%s%s", s, t);
can = true;
int lens = strlen(s);
int lent = strlen(t);
for (i = 0; i < lens; i++)
a[s[i] - 'a']++;
for (i = 0; i < lent; i++)
b[t[i] - 'a']++;
int more = 0;
for (i = 0; i < 26; i++)
{
if (a[i] < b[i])
can = false;
if (a[i] > b[i])
more++;
}
int cnt;
if (can && more)
{
cnt = lent;
for (i = 0; i < 26; i++)
for (j = 0; j < a[i] - b[i]; j++)
t[cnt++] = 'a' + i;
t[cnt] = '\0';
printf("%s\n", t);
return 0;
}
flag = false;
for (i = lent - 1; i >= 0; i--)
{
can = true;
b[t[i] - 'a']--;
for (j = 0; j < 26; j++)
if (a[j] < b[j])
can = false;
if (!can)
continue;
for (j = 0; j < 26; j++)
if (j > t[i] - 'a' && a[j] > b[j])
{
flag = true;
a[j]--;
t[i] = 'a' + j;
cnt = i + 1;
for (i = 0; i < 26; i++)
for (j = 0; j < a[i] - b[i]; j++)
t[cnt++] = 'a' + i;
t[cnt] = 0;
printf("%s\n", t);
break;
}
if (flag)
break;
}
if (!flag)
printf("-1\n");
return 0;
}
F-Cubes
题意:给你n个数 m种颜色 最多可以删k个数 问你最长连续颜色相同的序列长度是多少
vector存每个颜色的位置,然后之后用尺取法,最后取最大的就好了
#include <bits/stdc++.h>
using namespace std;
vector<int>v[111111];
int main()
{
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for (int i = 1 ; i <= n ; i++ )
{
int a;
scanf("%d",&a);
v[a].push_back(i);
}
int res = 1;
for (int i = 1 ; i <= m ; i++ )
{
int x = v[i].size();
int temp = 1;
int cou = 0;
int y = 0;
for(int j = 1 ; j < x ; j ++ )
{
temp++;
cou += v[i][j] - v[i][j-1] - 1;
while ( cou > k)
{
temp--;
cou -=v[i][y+1] - v[i][y] - 1;
y++;
}
if ( res < temp)
{
res = temp;
}
}
}
printf("%d\n",res);
}
G-Weak Memory
题目大意:给你一些关键点,然后从关键点可以充能,然后每走一步消耗1能量,然后问是否能从s走到t,问消耗P最大的最小。可二分能量P验证也可搜索。
这里用的是基于优先队列的BFS
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
const int inf=0x3f3f3f3f;
struct node
{
int to,next;
}e[maxn*2];
struct lu
{
int u;
int cost;
bool operator <(const lu &k)const{
return k.cost<cost;
}
}p,pp;
int head[maxn],dis[maxn];
int cnt,n,k,m,x,y,st,ed;
int a[maxn];
void add(int x,int y)
{
e[cnt].to=y;
e[cnt].next=head[x];
head[x]=cnt++;
}
priority_queue<lu> q;
int bfs()
{
int ans=0;
p.u=st;
p.cost=0;
q.push(p);
for(int i=1;i<=n;i++)dis[i]=inf;
dis[st]=0;
while(!q.empty())
{
p=q.top();
q.pop();
int u=p.u;
if(p.cost>dis[u])continue;
ans=max(ans,p.cost);
if(u==ed)return ans;
if(a[u])dis[u]=0;
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(dis[v]>dis[u]+1)
{
dis[v]=dis[u]+1;
pp.u=v;
pp.cost=dis[v];
q.push(pp);
}
}
}
return dis[ed];
}
int main()
{
cin>>n>>m>>k;
for(int i=1;i<=k;i++)
{
cin>>x;
a[x]=1;
}
memset(head,-1,sizeof(head));
for(int i=1;i<=m;i++)
{
cin>>x>>y;
add(x,y);
add(y,x);
}
cin>>st>>ed;
int ans=bfs();
if(ans==inf)puts("-1");
else cout<<ans<<endl;
return 0;
}
H-Divisible by Seven
给一个数,这个数包含1689,随意调换数字的位置,构造一个mod 7 = 0 的数字
为什么要包含1689这四个数字呢?就是因为1689可以构造出mod 7 = {0, 1 … 6 } 的所有数字.这样就可以挑出个1689 ,根据剩下的数字 mod 7 的余数, 得到适当的数字,加到那个数字的后面根据同余的运算规则,总可以构造出来。建议暴力找规律,规律之一在代码里有实现
#include<bits/stdc++.h>
using namespace std;
string s[10];
int main()
{
s[0]="1869";
s[1]="6198";
s[2]="1896";
s[3]="1689";
s[4]="9168";
s[5]="6189";
s[6]="1698";
string c;
cin>>c;
int l=c.size();
int a[22]={0};
for(int i=0;i<l;i++)
{
a[c[i]-'0']++;
}
a[1]--;
a[9]--;
a[6]--;
a[8]--;
string ans="";
int m=0;
for(int i=1;i<10;i++)
{
for(int j=1;j<=a[i];j++)
{
m=(m*10+i)%7;
ans+='0'+i;
}
}
ans+=s[m];
for(int i=1;i<=a[0];i++)ans+='0';
cout<<ans<<endl;
return 0;
}
I-Shooting Gallery
题意:给出n个靶子的坐标(x, y),出现的时间t,以及击中靶子的概率p;枪每秒移动一个单位的距离;问击中靶子数的期望最大值;
思路:dp[i] 表示到i为止击中靶子数的期望最大值;
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e3+10;
struct node
{
int x,y,t;
double p;
bool operator <(const node &k)const
{
return t<k.t;
}
}a[maxn];
double dp[maxn],ans=0;
double dis(double x1, double y1, double x2, double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i].x>>a[i].y>>a[i].t>>a[i].p;
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++)
{
dp[i]=a[i].p;
for(int j=1;j<i;j++)
{
if(a[i].t-a[j].t>=dis(a[i].x, a[i].y, a[j].x, a[j].y))
dp[i] = max(dp[i], dp[j]+a[i].p);
}
ans=max(dp[i],ans);
}
printf("%.10f\n",ans);
return 0;
}