1.https://www.luogu.org/problemnew/show/CF827A
/*首先考虑暴力,那就是每次for,显然时间无法承受
如果我们知道开头最远能到哪,就可以节省时间了,那我们
将以i开头向右最远能到的点记作fa[i]也就是关键点*/
#include<bits/stdc++.h>
using namespace std;
const int N=4e6+1;
int n,x,num,pos,maxn,fa[N];
char ans[N],s[N];
int getfa(int x){return fa[x]==x? x:fa[x]=getfa(fa[x]);}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d",&n);
for(int i=1;i<=4000000;i++)fa[i]=i;
for(int i=1;i<=n;i++){
scanf("%s",s+1);
int len=strlen(s+1);
scanf("%d",&num);
for(int j=1;j<=num;j++){
scanf("%d",&x);
maxn=max(maxn,x+len-1);
pos=x;
while(1){
pos=getfa(pos);
if(pos>x+len-1)break;//最右端超过本身长度显然要break
ans[pos]=s[pos-x+1];//更新当前点信息
fa[pos]=fa[getfa(pos+1)];//将pos合并到pos+1
pos=fa[pos];//找到下一个没有被覆盖的点
}
}
}
for(int i=1;i<=maxn;i++){
if(ans[i]=='\0')putchar('a');
else putchar(ans[i]);
}
return 0;
}
2.http://codeforces.com/contest/1063
/*
我怎么连bfs都不会写了啊
刚开始还以为直接bfs就行了,没想到我还是too youung
由于左右步数有限制,所以第一次bfs的不一定是最优解
那么发现同时记录向左和向右的最优解在更新。。。不太好写啊
看了题解后:
我们可以发现对于一个点我们只关心走到它向左最少走多少步即可
因为向左步数越少,向右步数就越少,然后就可以做了
就是0/1bfs 双端队列即可(第一次写双端队列)QAQ
0/1bfs逐层扩展保证最先搜到的就是最优解
附上失败代码:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=2100;
struct node{int x,y;}q[5000000];
int n,m,r,c,limitx,limity,tot=1,head=1,tail=0,v[N][N],lc[N][N],rc[N][N];
char a[N][N];
void bfs(int lx,int ly){
q[++tail].x=lx,q[tail].y=ly;
v[lx][ly]=1;
while(head<=tail){
int x=q[head].x,y=q[head].y;head++;
int xx,yy;
{
xx=x-1,yy=y;
if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
lc[xx][yy]=lc[x][y];
rc[xx][yy]=rc[x][y];
q[++tail].x=xx;
q[tail].y=yy;
v[xx][yy]=1;
tot++;
}
xx=x+1,yy=y;
if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
lc[xx][yy]=lc[x][y];
rc[xx][yy]=rc[x][y];
q[++tail].x=xx;
q[tail].y=yy;
v[xx][yy]=1;
tot++;
}
}
{
if(lc[x][y]<limitx){
xx=x,yy=y-1;
if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
lc[xx][yy]=lc[x][y]+1;
rc[xx][yy]=rc[x][y];
q[++tail].x=xx;
q[tail].y=yy;
v[xx][yy]=1;
tot++;
}
}
if(rc[x][y]<limity){
xx=x,yy=y+1;
if(xx>0&&xx<=n&&yy>0&&yy<=m&&!v[xx][yy]&&a[xx][yy]!='*'){
lc[xx][yy]=lc[x][y];
rc[xx][yy]=rc[x][y]+1;
q[++tail].x=xx;
q[tail].y=yy;
v[xx][yy]=1;
tot++;
}
}
}
}
}
int main()
{
freopen("a.in","r",stdin);
scanf("%d%d%d%d%d%d",&n,&m,&r,&c,&limitx,&limity);
rep(i,1,n)rep(j,1,m)cin>>a[i][j];
bfs(r,c);
cout<<rc[6][3];
//out<<tot;
return 0;
}*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=3000;
struct node{int x,y;node(int _x=0,int _y=0){x=_x;y=_y;}};
int n,m,r,c,limitx,limity,tot=0,d[N][N],v[N][N];
int dx[4]={0,1,-1,0};
int dy[4]={1,0,0,-1};
char a[N][N];
deque<node> q;
void bfs(int sx,int sy){
memset(d,-1,sizeof(d));
q.push_front(node(sx,sy));
d[sx][sy]=0;
while(q.size()){
node t=q.front();q.pop_front();
rep(i,0,3){
int x=t.x+dx[i],y=t.y+dy[i];
if(x<1||x>n||y<1||y>m||a[x][y]=='*'||(d[x][y]!=-1&&d[x][y]<=d[t.x][t.y]+(i==3)))continue;
d[x][y]=d[t.x][t.y]+(i==3);
if(i==3)q.push_back(node(x,y));
else q.push_front(node(x,y));
}
}
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d%d%d%d%d%d",&n,&m,&r,&c,&limitx,&limity);
rep(i,1,n)rep(j,1,m)cin>>a[i][j];
bfs(r,c);
rep(i,1,n){
rep(j,1,m){
if(d[i][j]==-1)continue;
int a=d[i][j],b=j-c+a;
if(a<=limitx&&b<=limity)tot++;
}
}
cout<<tot;
return 0;
}
3.https://www.luogu.org/problemnew/show/CF1060E
/*
将题意化简后就变成了求∑∑(dis(i,j)+1)/2;
感觉思想江化了啊,看题解,后来才想明白
∑∑dis(i,j)/2其实是很好算的吧
如果dis(i,j)是偶数,那么答案就是 (1/2)* ∑∑dis(i,j)
但是有距离是奇数的边,那我们可以发现答案就是 (1/2)* (∑∑dis(i,j)+奇数边个数)
证明不是很会,还涉及太多分类讨论 就当结论记住吧
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
struct node{int y,n;}e[N];
int deep[N],size[N],lin[N],len=0,num=0,n,x,y;
long long ans=0;
void read(int x,int y){e[++len].y=y,e[len].n=lin[x],lin[x]=len;}
void dfs(int x,int fa){
size[x]=1;
for(int i=lin[x];i;i=e[i].n){
int y=e[i].y;
if(y==fa)continue;
deep[y]=deep[x]+1;
dfs(y,x);
size[x]+=size[y];
}
}
int main()
{
scanf("%d",&n);
rep(i,1,n-1){scanf("%d%d",&x,&y);read(x,y),read(y,x);}
dfs(1,1);
rep(i,1,n){
ans+=1LL*size[i]*(n-size[i]);
if(deep[i]%2)num++;
}
ans+=1LL*num*(n-num);
cout<<ans/2;
return 0;
}
4.http://codeforces.com/problemset/problem/999/E
/*
tarjan缩点,形成一个DAG,那么就找入度为0的点,如果有入度为0的点
且这个点不是起点,那么就需要向这个点连一条边,否则就不用,好像
如果入度不为0,那么不管怎样都能到达这个点,(感性理解一下是对的QAQ)
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
stack<int> S;
struct node{int x,y,n;}e[N];
int lin[N],dfn[N],low[N],inv[N],du[N],c[N],scc=0,tot=0,ans=0,len=0,x,y,n,m,s;
void read(int x,int y)
{e[++len].y=y,e[len].x=x,e[len].n=lin[x],lin[x]=len;}
void tarjan(int x){
dfn[x]=low[x]=++tot;
S.push(x); inv[x]=1;
for(int i=lin[x];i;i=e[i].n){
int y=e[i].y;
if(!dfn[y]){
tarjan(y);
low[x]=min(low[x],low[y]);
}else if(inv[y]) low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x]){
int now=0;scc++;
while(now!=x){
now=S.top();S.pop();
inv[now]=0;
c[now]=scc;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
rep(i,1,m){scanf("%d%d",&x,&y);read(x,y);}
rep(i,1,n)if(!dfn[i])tarjan(i);
rep(i,1,len){
x=e[i].x,y=e[i].y;
if(c[x]==c[y])continue;
du[c[y]]++;
}
rep(i,1,scc)if(du[i]==0&&c[s]!=i)ans++;
cout<<ans;
return 0;
}
5.http://codeforces.com/problemset/problem/1003/E
/*
可以发现度数的限制其实容易解决,那么难点就在直径上
我想的是先解决度数再去调整直径,显然很不可做
看了题解才知道先构造直径,再去在直径上挂点
link(i,i+1)(i=1 to d )
显然一个点上挂的深度最多为min(i-1,d-i+1)
dfs挂点就行了
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
using namespace std;
const int N=1e6;
struct node{int x,y;}e[N];
int n,d,k,now=0,len=0;
void read(int x,int y){e[++len].x=x,e[len].y=y;}
void dfs(int x,int deep,int maxn){
if(deep==maxn)return;
for(int i=1;i<=k-1-(deep==0)&&now<n;i++){
read(x,++now);
dfs(now,deep+1,maxn);
}
}
int main()
{
scanf("%d%d%d",&n,&d,&k);
rep(i,1,d)read(i,i+1);
now=d+1;
rep(i,2,d)dfs(i,0,min(i-1,d-i+1));
if(now<n||k<2&&d>1||n<=d){cout<<"NO\n";return 0;}
cout<<"YES\n";
rep(i,1,len)printf("%d %d\n",e[i].x,e[i].y);
return 0;
}