题目编号 | 标题 |
---|---|
0 | 【GDKOI2004】石子游戏(game) |
1 | 【GDKOI2004】汉诺塔(hanoi) |
2 | 【GDKOI2004】城市统计(city) |
3 | 【GDKOI2004】香樟树(camphor) |
小勇和小实是对好朋友,他们经常一起游戏。 今天他们玩的游戏是这样的:有一个由正方形石头铺成的地板,它的高是2,长度是N。 例如以下是N=3的情况:
现在他们轮流在上面放上长宽分别是1和2的矩形石块,可以横放也可以竖放,但要刚好铺在地板上两个未被覆盖的正方形石头上,当某人不能放上去时他就输了。
例如,某次游戏可能是这样的,小实横放石块在左上面,如下:
然后小勇横放石块在右下面,如下:
这时小实不能再放石块了,所以他输了。小勇比较礼让,他让小实先放。当然,以上的方法可能不是最好的,现在假如他们都绝顶聪明,请你编程判断究竟谁会赢。
第一行一个整数C(1<=C<=100),表示测试数据的个数。 接下来有C行,每行为一个测试数据,每个测试数据只有一个整数N(1<=N<=100)。
输出C行,每行输出相应测试数据的结果。对于每个结果,如果是小勇赢的话就输出xiaoyong,否则就是小实赢啦,输出xiaoshi。
1
1
xiaoshi
这题只要判断奇偶
证明:小石先放,如果小石放横的,小勇也放横的
小石放竖的,小勇也放竖的
最后只要判断长度即可
#include
#include
using namespace std;
int n;
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
int t;
cin>>t;
while(t--){
cin>>n;
if(n%2==1)cout<<"xiaoshi"<<endl;
else cout<<"xiaoyong"<<endl;
}
return 0;
}
古老的汉诺塔问题是这样的:用最少的步数将N个半径互不相等的圆盘从1号柱利用2号柱全部移动到3号柱,在移动的过程中小盘要始终在大盘的上面。 现在再加上一个条件:不允许直接把盘从1号柱移动到3号柱,也不允许直接把盘从3号柱移动到1号柱。 把盘按半径从小到大用1到N编号。每种状态用N个整数表示,第i个整数表示i号盘所在的柱的编号。则N=2时的移动方案为: (1,1)=>(2,1)=>(3,1)=>(3,2)=>(2,2)=>(1,2)=>(1,3)=>(2,3)=>(3,3) 初始状态为第0步,编程求在某步数时的状态。
输入文件的第一行为整数T(1<=T<=50000),表示输入数据的组数。 接下来T行,每行有两个整数N,M(1<=n<=19,0<=M<=移动N个圆盘所需的步数)。
输出文件有T行。 对于每组输入数据,输出N个整数表示移动N个盘在M步时的状态,每两个数之间用一个空格隔开,行首和行末不要有多余的空格。
4
2 0
2 5
3 0
3 1
1 1
1 2
1 1 1
2 1 1
这题只要找规律
通过大佬所说,第一个圆盘会被移动3次,第二个会移动9次,第三个会移动27次……
依次类推,找规律即可:
#include
#include
#include
using namespace std;
int m,n,k,x,y;
int a[6]={1,2,3,3,2,1};//放的过程中是递增或递减的,所以1-2-3-3-2-1
int ans[1001];
int main(){
freopen("hanoi.in","r",stdin);
freopen("hanoi.out","w",stdout);
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
k=0;
while(m!=0){
k++;
ans[k]=a[m%6];
m/=3;//每次除三,算出这个圆盘移动了多少次
}
if(ans[1]==0)printf("1");
else printf("%d",ans[1]);
ans[1]=0;
for(int i=2;i<=n;i++){
if(ans[i]==0)printf(" 1");
else printf(" %d",ans[i]);
ans[i]=0;
}
printf("\n");
}
return 0;
}
中山市的地图是一个n*n的矩阵,其中标号为1的表示商业区,标号为0的表示居民区。为了考察市内居民区与商业区的距离,并对此作出评估,市长希望你能够编写一个程序完成这一任务。 居民区i到商业区的距离指的是到距离它最近的商业区j的距离(|Xi-Xj|+|Yi-Yj|)(你可以理解为他们的行列分别作差),而你将统计的是对于城市中的每一个区域k,以它为中心的(2*r+1)*(2*r+1)的矩阵区域内所有居民区到商业区的距离总和。结果同样以n*n的矩阵形式输出。
第一行为t,表示以下有t组数据,每组数据之间以空行隔开,以下:
第一行为n,r(1<=r
t组n*n的矩阵。每组用空行隔开
1
4 1
1 0 0 0
1 1 0 0
0 1 1 0
0 1 0 0
1 4 9 8
2 5 10 9
2 4 7 7
2 3 4 4
这题广搜+前缀和
用广搜算出距离,用前缀和求出总和,用判断造就AC
#include
#include
#include
using namespace std;
int m,n,k,x,y,a[200][200],b[200][200],f[40000][4],bz[200][200];
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
void bfs(int x,int y){
f[1][1]=x;f[1][2]=y;f[1][3]=0;
bz[x][y]=k;
int head=0,tail=1;
while(head<tail){
head++;
for(int i=0;i<4;i++){
int xx=f[head][1]+dx[i];
int yy=f[head][2]+dy[i];
if(xx<1||xx>n||yy<1||yy>n
||bz[xx][yy]==k)continue;
tail++;
f[tail][1]=xx;
f[tail][2]=yy;
f[tail][3]=f[head][3]+1;
if(a[xx][yy]==1){
b[x][y]=f[tail][3];
return;
}
bz[xx][yy]=k;
}
}
}
int main(){
freopen("city.in","r",stdin);
freopen("city.out","w",stdout);
int t;
cin>>t;
while(t--){
k=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
k++;
if(a[i][j]==0){
bfs(i,j);
}
}
}
memset(a,0,sizeof(a));
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
a[i][j]=b[i][j]+a[i-1][j]+a[i][j-1]-a[i-1][j-1];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int x=max(i-m,1);
int y=max(j-m,1);
int xx=min(i+m,n);
int yy=min(j+m,n);
cout<<a[xx][yy]-a[x-1][yy]-a[xx][y-1]+a[x-1][y-1]<<' ';
}
cout<<endl;
}
cout<<endl;
memset(bz,0,sizeof(bz));
memset(b,0,sizeof(b));
}
return 0;
}
被誉为江南四大名木之一的香樟树很有特色,它的树皮粗糙,质地却很均匀,从来没有白杨树的斑斑驳驳、没有柳树的肿瘤结节;树枝树干一分为二、二分为四一路长去,不会偷工减料也不会画蛇添足;树冠的形态是球形的,在天空中画出优美的曲线。 除了上述优点之外,香樟树还有一个秘密武器。那就是……………………它凭借朴实、厚重的优秀品格赢得了小狐狸的青睐!!! 话说有一天,小狐狸正在湖边散步,忽然一阵风吹来,她赶紧闭上眼睛。当她再次睁开眼睛时,发现美丽的湖畔多出了一排整齐的香樟树。小狐狸非常兴奋,她对每棵树都观察入微,并且数出了它们的叶子个数。她觉得如果相邻两棵树的叶子个数互素是不和谐的。因此小狐狸想从一排香樟树中选出若干棵,在满足相邻两棵树的叶子个数不互素的条件下,使得树尽量多。
第一行一个正整数n,表示有n棵香樟树。 第二行n个正整数,第i个数表示第i棵香樟树叶子的个数。
一个正整数,表示最多能选多少棵树。
6
6 2 3 15 8 5
4
对于60%的数据n<=1000
对于100%的数据 n<=100000,叶子个数<=100000
注意:选中的树不能改变其位置,即如果选中第(t1,t2,t3……tn)棵树 ,其中t1
选择第1、第3、第4和第6棵树
忠告:
如果一个比赛里3题都不是DP,那剩下那题有9成几率是DP
普通的最长不下降子序列60分
我们可以设由i结尾可以最多选多少个
f[i]=max(f[i],t[j]+1)
其中t为分解质因数后每个质因子出现的次数
应为两对不是互质数的数有一个数相同,那这三个数都不互质
由这一点就可以推出:
t[j]=f[i]
f数组1~100000中的最大值即为所求:
#include
#include
#include
using namespace std;
int m,n,k,x,y;
int a[1001000],ss[100010],t1[100100],t[1001000],f[100100];
void dp(){
for(int i=1;i<=n;i++){
int j=a[i];
t1[0]=0;
int k=1;
while(j!=1){
if(j%ss[k]==0){
t1[0]++;
t1[t1[0]]=ss[k];
while(j%ss[k]==0){
j/=ss[k];
}
}
k++;
}
for(int j=1;j<=t1[0];j++)
f[i]=max(f[i],t[t1[j]]+1);
for(int j=1;j<=t1[0];j++)
t[t1[j]]=f[i];
}
int ans=0;
for(int i=1;i<=100000;i++)
ans=max(ans,f[i]);
cout<<ans;
}
void s(){
for(int i=2;i<=100000;i++){
int f=0;
for(int j=2;j<=sqrt(i);j++)
if(i%j==0){
f=1;
break;
}
if(f==0){
ss[0]++;
ss[ss[0]]=i;
}
}
}
int main(){
freopen("camphor.in","r",stdin);
freopen("camphor.out","w",stdout);
s();
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
dp();
return 0;
}