首先说下这场比赛我不是隔天过的,当时是我参赛的。很可惜只过了三题,第四题实在是想不出来。而且过三题的速度十分之慢,还没有学弟快,一个是因为我的读题速度实在是感人,还有我的写法一般也是十分之恶心。唉,真TM丢人。
A. Crazy Computer
分析:给你n个数,求最后有多少个连续且相邻两个数之间的差值不超过c的个数。一开始我以为是很简单的题目,照着题意模拟即可。卧槽,写这篇题解的时候想到了,模拟个p,直接从最后搜索找到连续个差值小于c的个数就直接输出了。我正着写的话,还要维护一个值,还难写。
int main(){
//freopen("d:\\acm\\in.in","r",stdin);
int n,c;
scanf("%d %d",&n,&c);
int a=-1,b;
int ans;
for(int i=0;i<n;i++){
if(a<0){
scanf("%d",&a);
ans=1;
}
else {
scanf("%d",&b);
if(b-a<=c){
ans++;
//cout<<ans<<endl;
a=b;
}
else {
ans=1;
a=b;
}
}
}
cout<<ans<<endl;
return 0;
}
B. Complete the Word
分析:给你一个字符串,只包含大写字母和?,?表示能和任何大写字母匹配(能够变成任何大写字母)。问给你的字符串能不能变成,存在至少一个长度为26的子串正好包含所有26个字母的字符串,如果能输出某一个这样的字符串,不能就输出-1。题目稍微有点复杂,但是思路还是比较好想的。其实就是先特判一下前26个字符(总长度如果小于26,直接-1)有没有可能成为那种子串(统计一下这26个字符中每个大写字母出现的次数,如果有出现大于等于2次的,那么显然是不能称为这种子串的,如果都不超过1的话就是可能的),不能就依次向下搜索,加上下一个字符的信息,删去最开始的字符的信息。还有,不要忘记将其他?随便一个字符。
char dat[maxn];
int num[30];
void buquan(int n){
for(int i=0;i<n;i++)
if(dat[i]=='?')
dat[i]='A';
}
int main(){
scanf("%s",dat);
int len=strlen(dat);
int cnt=0;
if(len<26){
puts("-1");
return 0;
}
for(int i=0;i<26;i++)
if(dat[i]!='?'){
num[dat[i]-'A']++;
if(num[dat[i]-'A']==2)cnt++;
}
if(!cnt){
int k=0;
for(int i=0;i<26;i++)
if(dat[i]=='?'){
while(num[k])
k++;
num[k]=1;
dat[i]='A'+k;
}
buquan(len);
printf("%s\n",dat);
return 0;
}
for(int i=26;i<len;i++){
if(dat[i-26]!='?'){
num[dat[i-26]-'A']--;
if(num[dat[i-26]-'A']==1)cnt--;
}
if(dat[i]!='?'){
num[dat[i]-'A']++;
if(num[dat[i]-'A']==2)cnt++;
}
if(!cnt){
int k=0;
for(int j=i-25;j<=i;j++)
if(dat[j]=='?'){
while(num[k])
k++;
num[k]=1;
dat[j]='A'+k;
}
buquan(len);
printf("%s\n",dat);
return 0;
}
}
puts("-1");
return 0;
}
C. Plus and Square Root
分析:这看起来是道难题,但是其实是一道找规律题。按照数字最小的原则(因为好算,而且统一起来就有规律了,题目没有要求),对于i,其实是要开根号得到
i∗(i−1)
,1的时候特判一下。那么就的到公式
(i∗(i+1))2−i∗(i−1)i=i3+2i2+1
,那么只要循环输出即可,1的时候要特判。你问我这道想法,就是找规律,你写出了前几项找找就行了。
int main(){
//freopen("d:\\acm\\in.in","r",stdin);
int n;
scanf("%d",&n);
puts("2");
for(int i=2;i<=n;i++){
printf("%lld\n",1ll*i*i*i+2ll*i*i+1);
}
return 0;
}
D. Complete The Graph
分析:给你一个有向图G(n,m),没有重边。你需要给定某些边的权值,使得s和t之间的最短路正好等于L。这是一道比较难的图论题,比赛的时候没有做出来,但是看完别人的代码恍然大悟,原来这么做。我们首先不妨将这些没有定义边权的边的边权都赋为最小的1 ,先跑一遍最短路,如果此时s和t都不能连通或者最短路大于L的话,那么不会有任何其他方法使得最短路变得更小,除非边权小于等于0;如果正好等于L的情况,那么正好输出;但是麻烦就是麻烦在小于L的情况,需要多次调试边权得到答案。这样看的话,这道题目更像一道构造题,感觉这么想的话,给我的启发又深了一层。我们遍历所有开始的时候没有边权的边,对于每一条边加上现在s和t之间的最短路与L之间的差值,然后重新跑一遍最短路,看一下s和t之间的最短路是否是L,如果不是的话,那么更新这个差值,对于下一条开始没有边权的边进行新一轮的操作。不过扫一遍还不能使得最短路等于L的话,说明其中最短路是由开始时有边权的边组成的。我感觉这做法是正确的,但是你要我证明那我还真的不会。但是我觉得这种方法不应该只用于这道题,好多其他构造题目都可以使用,学到一招。
#include <map>
#include <set>
#include <ctime>
#include <stack>
#include <cmath>
#include <queue>
#include <bitset>
#include <string>
#include <vector>
#include <cstdio>
#include <cctype>
#include <fstream>
#include <cstdlib>
#include <sstream>
#include <cstring>
#include <iostream>
#include <algorithm>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define maxn 10000+10
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define clr(x,y) memset(x,y,sizeof(x))
#define rep(i,n) for(int i=0;i<(n);i++)
#define repf(i,a,b) for(int i=(a);i<=(b);i++)
#define pii pair<int,int>
#define mp make_pair
#define FI first
#define SE second
#define IT iterator
#define PB push_back
#define Times 10
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const double eps = 1e-10;
const double pi = acos(-1.0);
const ll mod = 1e9+7;
const int inf = 0x3f3f3f3f;
const ll INF = (ll)1e18+300;
const double delta = 0.98;
inline void RI(int& x)
{
x=0;
char c=getchar();
while(!((c>='0'&&c<='9')||c=='-'))c=getchar();
bool flag=1;
if(c=='-')
{
flag=0;
}
while(c<='9'&&c>='0')
{
x=x*10+c-'0';
c=getchar();
}
if(!flag)x=-x;
}
struct edge{
int u,v;
ll w;
int next;
}dat[maxn<<1];
int n,m,edgenum;
int head[maxn];
int mark[maxn];
bool vis[maxn];
ll dis[maxn];
void add_edge(int u,int v,ll w){
dat[edgenum].u=u;
dat[edgenum].v=v;
dat[edgenum].w=w;
dat[edgenum].next=head[u];
head[u]=edgenum++;
}
void spfa(int s){
queue<int>q;
for(int i=0;i<n;i++){
vis[i]=false;
dis[i]=inf;
}
dis[s]=0;
vis[s]=true;
q.push(s);
while(!q.empty()){
int x=q.front();
q.pop();
vis[x]=false;
for(int i=head[x];i!=-1;i=dat[i].next){
int y=dat[i].v;
ll xy=dat[i].w;
if(dis[x]+xy<dis[y]){
dis[y]=dis[x]+xy;
if(!vis[y]){
vis[y]=true;
q.push(y);
}
}
}
}
}
void print(){
puts("YES");
for(int i=0;i<m;i++)
printf("%d %d %lld\n",dat[i*2].u,dat[i*2].v,dat[i*2].w);
}
int main(){
ll L;
int x,y;
scanf("%d %d %lld %d %d",&n,&m,&L,&x,&y);
edgenum=0;
clr(head,-1);
for(int i=0;i<m;i++){
int u,v;
ll w;
scanf("%d %d %lld",&u,&v,&w);
if(w==0){
w=1;
mark[i]=1;
}
add_edge(u,v,w);
add_edge(v,u,w);
}
spfa(x);
if(dis[y]==inf||dis[y]>L)puts("NO");
else if(dis[y]==L)print();
else {
ll tmp=L-dis[y];
for(int i=0;i<m;i++)
if(mark[i]){
dat[i*2].w+=tmp;
dat[i*2+1].w+=tmp;
spfa(x);
tmp=L-dis[y];
if(tmp==0){
print();
return 0;
}
}
puts("NO");
}
return 0;
}
继续努力,争取以后四题上紫。