CF 400A. Inna and Choose Options
题目链接:
http://codeforces.com/problemset/problem/400/A
题目意思:
给只含‘X'和’O'字符的长度为12的字符串,将它写入矩阵a*b(a*b=12)中,问存在某一列全为‘X'的矩阵的个数。
解题思路:
枚举。一共只有1*12,2*6,3*4,4*3,6*2,12*1六种。
代码:
//#include<CSpreadSheet.h>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
char save[25];
int a[10]={0,1,2,3,4,6,12}; //保存六种情况
vector<int>myv;
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t;
scanf("%d",&t);
while(t--)
{
myv.clear();
scanf("%s",save+1);
int ans=0;
for(int i=1;i<=6;i++)
{
int aa=a[i];
int bb=12/a[i];
bool flag=false;
for(int j=1;j<=bb;j++)
{
bool tt=true;
for(int k=1;k<=aa;k++)
{
if(save[(k-1)*bb+j]!='X')
{
tt=false;
break;
}
}
if(tt)
{
flag=true;
break;
}
}
if(flag)
{
ans++;
myv.push_back(a[i]);//保存结果集
}
}
printf("%d ",ans);
for(int i=0;i<myv.size();i++)
printf("%dx%d ",myv[i],12/myv[i]);
putchar('\n');
}
return 0;
}
CF 400B. Inna and New Matrix of Candies
题目链接:
http://codeforces.com/contest/400/problem/B
题目意思:
给n*m的方格,每行中都且仅有一个方格含S和G,每一步可以使所有的G向右移,只到发生下列情况:1、某个G已到了最后一列。2、某个G已到了S。求把所有的G已到S需要的最少的步数。
解题思路:
统计S-G差出现的个数。
代码:
//#include<CSpreadSheet.h>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define Maxn 1100
char save[Maxn][Maxn];
int n,m;
int gap[Maxn];
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d",&n,&m))
{
bool flag=true;
memset(gap,0,sizeof(gap));
for(int i=1;i<=n;i++)
{
scanf("%s",save[i]+1);
int g,s;
for(int j=1;j<=m;j++)
{
if(save[i][j]=='G')
g=j;
else if(save[i][j]=='S')
s=j;
}
if(g>s)
flag=false;
else
gap[s-g]++;
}
if(!flag)
{
printf("-1\n");
continue;
}
int ans=0;
for(int i=1;i<=m;i++)
if(gap[i])
ans++;
printf("%d\n",ans);
}
return 0;
}
CF 400C C. Inna and Huge Candy Matrix
题目链接:
http://codeforces.com/problemset/problem/400/C
题目意思:
给一个矩阵,求经过顺时针旋转90度x次,左右翻转y次,逆时针旋转90度z次,坐标(x,y)对应的新坐标。
解题思路:
上面三种变换可以统一成几个简单的基本操作。详细可以参考我的这篇博客:http://blog.csdn.net/cc_again/article/details/18007891
这题相对比较简单,可以先对x%=4,y%=2,z=(4-z%4)%4(转化成顺时针的情况),然后对于每个坐标,分别实行上述操作,即可得到答案。
代码:
//#include<CSpreadSheet.h>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
int n,m;
int tempn,tempm;
void C90(int &x,int &y) //顺时针旋转90度
{
int temp=x;
x=y;
y=tempn-temp+1;
swap(tempn,tempm);
}
void hh(int &x,int &y) //左右翻转
{
y=tempm-y+1;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int x,y,z,p;
while(~scanf("%d%d",&n,&m))
{
scanf("%d%d%d%d",&x,&y,&z,&p);
x=x%4; //顺时针的次数
z=(4-z%4)%4; //转化为顺时针的次数
y=y%2; //左右翻转
for(int i=1;i<=p;i++)
{
int a,b;
scanf("%d%d",&a,&b);
tempn=n,tempm=m;
for(int i=1;i<=x;i++)
C90(a,b);
if(y)
hh(a,b);
for(int i=1;i<=z;i++)
C90(a,b);
printf("%d %d\n",a,b);
}
}
return 0;
}
题目链接:
http://codeforces.com/problemset/problem/400/D
题目意思:
这题意思有点搞人,有k种细菌,第i种有ci个,按顺序编号,一共有n个细菌。告诉细菌之间传递能量所需的价值。问是否存在对于任何种类i,该种所有细菌相互传递能量的价值都为0(可以传递)。存在就输出Yes,并输出任意两种细菌传递能量的最小值,否则只用输出No.
解题思路:
floyd+并查集+二分
如果价值为零,则添加到一个集合里,如果同种的细菌的fa相同,则说明该种细菌之间传递价值都为0。
对于不同种类的细菌,更新种类之间传递的最小值,用floyd求出任意两种之间的能量传递最小值。
sum[i]:保存第i种细菌的最后一个细菌编号,二分可以求出属于第几种细菌。
代码:
//#include<CSpreadSheet.h>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define Maxn 110000
#define Maxm 550
int sum[Maxn],save[Maxm];
int n,m,k;
int fa[Maxn],dis[Maxm][Maxm];
void init()
{
for(int i=1;i<=n;i++)
fa[i]=i;
memset(dis,INF,sizeof(dis));
for(int i=1;i<=k;i++)
dis[i][i]=0;
}
int find(int x)
{
if(fa[x]!=x)
return fa[x]=find(fa[x]);
return x;
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
while(~scanf("%d%d%d",&n,&m,&k))
{
init();
sum[0]=0;
for(int i=1;i<=k;i++)
{
scanf("%d",&save[i]);
sum[i]=sum[i-1]+save[i];
}
for(int i=1;i<=m;i++)
{
int a,b,c;
int fa_a,fa_b,loc_a,loc_b;
scanf("%d%d%d",&a,&b,&c);
loc_a=lower_bound(sum+1,sum+k+1,a)-sum; //求出该细菌所属种类
loc_b=lower_bound(sum+1,sum+k+1,b)-sum;
if(loc_a!=loc_b) //说明不是同一种
dis[loc_a][loc_b]=dis[loc_b][loc_a]=min(dis[loc_a][loc_b],c);
if(c==0)
{
fa_a=find(a);
fa_b=find(b);
if(fa_a!=fa_b)
fa[fa_b]=fa_a;
}
}
bool ans=true;
for(int i=1;i<=k;i++)
{
int temp=find(sum[i-1]+1); //该种第一个细菌所在集合
bool flag=true;
for(int j=sum[i-1]+2;j<=sum[i];j++) //
{
if(find(j)!=temp)
{
flag=false;
break;
}
}
if(!flag)
{
ans=false;
break;
}
}
if(!ans)
{
printf("No\n");
continue;
}
printf("Yes\n");
for(int p=1;p<=k;p++) //floyd
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(dis[i][p]+dis[p][j]<dis[i][j])
dis[i][j]=dis[j][i]=dis[i][p]+dis[p][j];
}
}
for(int i=1;i<=k;i++)
{
for(int j=1;j<=k;j++)
{
if(dis[i][j]==INF)
printf("-1 ");
else
printf("%d ",dis[i][j]);
}
putchar('\n');
}
}
return 0;
}
CF 400 E E. Inna and Binary Logic
题目链接:
http://codeforces.com/problemset/problem/400/E
题目意思:
给定n个数a1[1..n],定义ak[i]=ak-1[i]&ak-1[i+1],则一共有n*(n-1)/2个数。有m种操作,每种操作ai,bi,表示把a1[ai]改成bi,求这n*(n-1)/2个数的和,改变是连续影响的。
解题思路:
二进制和数据结构。
按位进行处理,mys[i]表示第i位为零是n个数中的哪几个。两个零之间一定是连续的1,扫描开始的n个数,对于每一位如果它为1,则找到大于它的第一个为0的位置,则这个1持续的次数就是他们之间的间隔。这样求出原始的总和。
操作主要分两种:
1、把当前位的0变成1。此时从当前的0到下一个0的间距是该位0所要增加的1的个数p,该零后面的将不受影响。该零前面的所有连续的1(假设为m个)都会增加p个。(从0往左下角45度对角线)故+m*p*位权。
2、把当前位的1变成0。与上述情况相反,-m*p*位权。
注意要连续更新原始数组,中间溢出情况。
代码:
//#include<CSpreadSheet.h>
#include<iostream>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstdlib>
#include<string>
#include<string.h>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<stack>
#include<list>
#include<queue>
#include<ctime>
#include<bitset>
#define eps 1e-6
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define ll __int64
#define LL long long
#define lson l,m,(rt<<1)
#define rson m+1,r,(rt<<1)|1
#define M 1000000007
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
#define Maxn 110000
set<int>mys[20]; //mys[i]保存第i位为零有哪几个数
int save[Maxn];
int main()
{
//cout<<(1<<20);
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<20;i++)
{
mys[i].clear();
mys[i].insert(0); //边界情况考虑进去
mys[i].insert(n+1);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&save[i]);
for(int j=0;j<20;j++)
{
if(!(save[i]&(1<<j)))
mys[j].insert(i); //统计j位为0的 哪几个情况
}
}
ll ans=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<20;j++)
{
if(save[i]&(1<<j)) //非零的情况
{
set<int>::iterator it=mys[j].upper_bound(i); //找到大于当前位置的第一个零的位置
ans+=(ll)(*it-i)*(1<<j);
}
}
}
//printf("%I64d\n",ans);
//system("pause");
for(int i=1;i<=m;i++)
{
int ri,va;
scanf("%d%d",&ri,&va);
for(int j=0;j<20;j++)
{
if((va&(1<<j))&&((save[ri]&(1<<j))==0)) //要把0改成1
{
set<int>::iterator it=mys[j].find(ri);
it++;
int rr=*it;
it--;
it--;
int le=*it;
ans+=(ll)(rr-ri)*(1<<j)*(ri-le);
mys[j].erase(ri);
}
else if(((va&(1<<j))==0)&&(save[ri]&(1<<j))) //把1变成0
{
mys[j].insert(ri);
set<int>::iterator it=mys[j].find(ri);
it++;
int rr=*it;
it--;
it--;
int le=*it;
ans-=(ll)(rr-ri)*(1<<j)*(ri-le);
}
}
printf("%I64d\n",ans);
save[ri]=va; //注意连续更新
}
}
return 0;
}