CF回滚以后掉到蓝名了,打了一场勉强回到div1,D最后复测竟然挂了,好伤心。。。
A Inna and Choose Options
长度为12的OX的序列,要排成a×b的矩阵,使得矩阵有一列全为X。很简单。随便枚举一下就行了。。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
char str[20];
char tmp[20][20];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t);
vector<pair<int,int> >ans;
while(t--)
{
scanf("%s",str);
ans.clear();
for(int b=12;b>=1;--b)
{
if(12%b!=0) continue;
int a=12/b;
bool flag=false;
for(int j=0;j<b;++j)
{
bool canit=true;
for(int i=0;i<a;++i)
if(str[i*b+j]!='X') {canit=false;break;}
if(canit) {flag=true;break;}
}
if(flag) ans.push_back(make_pair(a,b));
}
int size=ans.size();
printf("%d",size);
for(int i=0;i<size;++i)
{
printf(" %dx%d",ans[i].first,ans[i].second);
}
printf("\n");
}
return 0;
}
B - Inna and New Matrix of Candies
这题最开始看了半天楞是没看懂,只要先去做C。。。其实就是给出一个矩阵,每一行只有一个G和一个S其他都是*,现在要把每一行的G都移动到S处。每次可以选若干行,使这一行的G同时向右移动,直到有一个G到达S或到达矩阵最右段。问最少需要多少操作。。先算一下每个G到达S的步数,接下来让离得最近的到达S,同时所有的G移动,然后让离得第二近的移动……只要排个序搞一下就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1000+10;
char str[maxn][maxn];
int step[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
scanf("%s",str[i]);
bool cansolve=true;
for(int i=0;i<n;++i)
{
bool flag=false;
int last=-1;
for(int j=0;j<m;++j)
{
if(str[i][j]=='G')
{last=j;flag=true;}
else if(str[i][j]=='S')
{
if(last==-1) break;
step[i]=j-last;
}
}
if(!flag) {cansolve=false;break;}
}
if(!cansolve)
printf("-1\n");
else
{
int cnt=0;
sort(step,step+n);
int k=n;
while(true)
{
cnt++;
int val=step[0];
int i=1;
for(i=1;i<k;++i)
step[i]-=val;
step[0]=0;
i=0;
while(step[i]==0&&i<k) i++;
if(i==k) break;
for(int j=0;j<k-i;++j)
step[j]=step[i+j];
k=k-i;
}
printf("%d\n",cnt);
}
return 0;
}
C - Inna and Huge Candy Matrix
给出一个n×m的矩阵,有p个位置有糖果,现在将这个矩阵顺时针旋转x次,翻转矩阵的行y次,逆时针旋转z次,问最后这p个点的位置。在纸上画一画就会发现每个操作后的位置都可以算出来,这样,将x,y,分别对4,2,4取模,然后依次模拟相应操作计算坐标就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Point
{
int x,y;
Point(){}
Point(int x,int y):x(x),y(y) {}
}pt[maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,X,Y,Z,p;
scanf("%d%d%d%d%d%d",&n,&m,&X,&Y,&Z,&p);
for(int i=0;i<p;++i)
scanf("%d%d",&pt[i].x,&pt[i].y);
X=X%4;Y%=2;Z%=4;
int N=n,M=m;
for(int i=0;i<p;++i)
{
n=N,m=M;
int x=pt[i].x,y=pt[i].y;
if(X==1) pt[i]=Point(y,n-x+1),swap(n,m);
else if(X==2) pt[i]=Point(n-x+1,m-y+1);
else if(X==3) pt[i]=Point(m-y+1,x),swap(n,m);
x=pt[i].x,y=pt[i].y;
if(Y) pt[i]=Point(x,m-y+1);
x=pt[i].x,y=pt[i].y;
if(Z==3) pt[i]=Point(y,n-x+1);
else if(Z==2) pt[i]=Point(n-x+1,m-y+1);
else if(Z==1) pt[i]=Point(m-y+1,x);
printf("%d %d\n",pt[i].x,pt[i].y);
}
return 0;
}
D - Dima and Bacteria
感觉这题也好难理解。。。有n个细菌,将这些细菌分为k种,每种有c[i]个,接下来有m条边表示从某个细菌到另一个细菌所需要耗费的能量。如果同种细菌之间任意两个细菌相互到达所需要的能量为0,那么就输出yes并输出不同种类细菌之间的最短距离。需要注意两个同种细菌可以经过其他不同种类的细菌到达。理解题意以后就比较简单了,如果边权为0,那么用并查集把这两个点合并,最后看相同种类的细菌是否都在同一个集合中。最后floyd一下就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Edge
{
int v,w,next;
Edge(){}
Edge(int v,int w,int next):v(v),w(w),next(next){}
}edges[maxn<<1];
int head[maxn],nEdge;
int type[maxn],c[maxn];
int pa[maxn];
int d[550][550];
void AddEdges(int u,int v,int w)
{
edges[++nEdge]=Edge(v,w,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,w,head[v]);
head[v]=nEdge;
}
int Find(int x)
{
return x==pa[x]?x:pa[x]=Find(pa[x]);
}
void Uion(int x,int y)
{
int a=Find(x),b=Find(y);
if(a!=b) pa[b]=a;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
int cnt=0,u,v,w;
memset(head,0xff,sizeof(head));
memset(d,0x3f,sizeof(d));
nEdge=-1;
for(int i=1;i<=n;++i) pa[i]=i;
for(int i=1;i<=k;++i)
{
scanf("%d",&c[i]);
for(int j=0;j<c[i];++j)
type[++cnt]=i;
}
for(int i=0;i<m;++i)
{
scanf("%d%d%d",&u,&v,&w);
AddEdges(u,v,w);
if(w==0)
Uion(u,v);
if(type[u]!=type[v])
d[type[u]][type[v]]=d[type[v]][type[u]]=min(d[type[u]][type[v]],w);
}
cnt=1;
bool flag=true;
for(int i=1;i<=k&&flag;++i)
{
int fa=Find(cnt);
for(int j=0;j<c[i];++j)
if(Find(cnt+j)!=fa) {flag=false;break;}
cnt+=c[i];
}
if(!flag)
printf("No\n");
else
{
for(int i=1;i<=k;++i) d[i][i]=0;
for(int v=1;v<=k;++v)
for(int i=1;i<=k;++i)
for(int j=1;j<=k;++j)
d[i][j]=min(d[i][j],d[i][v]+d[v][j]);
printf("Yes\n");
for(int i=1;i<=k;++i)
{
for(int j=1;j<=k;++j)
{
if(j!=1) printf(" ");
if(d[i][j]==inf) d[i][j]=-1;
printf("%d",d[i][j]);
}
printf("\n");
}
}
return 0;
}
E - Inna and Binary Logic
最初给出n个序列,对序列要进行n-1次操作,每次令ai[k] = ai - 1[k] AND ai - 1[k + 1].问所有操作过程中的序列的和。开始没什么思路,看了看过掉的代码,发现完全看不懂这些大牛们的高大上的方法,不过也有所启发,yy了一下,想了个麻烦的方法、、、、首先把每个数按位建17棵线段树,对于每一位,将整个操作列出来可以发现,如果这个序列每有连续k个1,那么最终操作的总和就要加上(k+1)*k/2。想了想,利用线段树区间合并的方法貌似能搞,val[]表示操作完这个区间后的总和,sum[]表示区间里1的个数,pre[]表示区间最长连续1的前缀数,suff[]表示区间最长连续的1的后缀数。然后用线段树维护即可。。。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
int num[maxn];
struct SegTree
{
int sum[maxn<<2],pre[maxn<<2],suff[maxn<<2];
ll val[maxn<<2];
int bitp;
void PushUp(int l,int r,int rt)
{
int m=(l+r)>>1;
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
if(sum[rt<<1]==m-l+1)
pre[rt]=sum[rt<<1]+pre[rt<<1|1];
else pre[rt]=pre[rt<<1];
if(sum[rt<<1|1]==r-m)
suff[rt]=suff[rt<<1]+sum[rt<<1|1];
else
suff[rt]=suff[rt<<1|1];
if(suff[rt<<1]&&pre[rt<<1|1])
{
val[rt]=val[rt<<1]+val[rt<<1|1];
ll tmp=suff[rt<<1];
val[rt]-=tmp*(tmp+1)/2;
tmp=pre[rt<<1|1];
val[rt]-=tmp*(tmp+1)/2;
tmp=suff[rt<<1]+pre[rt<<1|1];
val[rt]+=tmp*(tmp+1)/2;
}
else
val[rt]=val[rt<<1]+val[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r)
{
val[rt]=sum[rt]=pre[rt]=suff[rt]=(num[l]>>bitp)&1;
return ;
}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
PushUp(l,r,rt);
}
void Update(int p,int l,int r,int rt,int v)
{
if(l==r)
{
sum[rt]=val[rt]=pre[rt]=suff[rt]=v;
return ;
}
int m=(l+r)>>1;
if(m>=p) Update(p,l,m,rt<<1,v);
else Update(p,m+1,r,rt<<1|1,v);
PushUp(l,r,rt);
}
}tree[17];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&num[i]);
for(int i=0;i<17;++i)
{
tree[i].bitp=i;
tree[i].build(1,n,1);
}
int p,v;
ll sum;
while(m--)
{
scanf("%d%d",&p,&v);
sum=0;
for(int i=0;i<17;++i)
{
tree[i].Update(p,1,n,1,(v>>i)&1);
sum+=(1<<i)*tree[i].val[1];
}
printf("%I64d\n",sum);
}
return 0;
}