TODO
1007 The Unsolvable Problem
难度不大,暴力枚举,从中间分开,查找互素的和数。
/****************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <stack>
#include <map>
#include <queue>
#include <algorithm>
#include <ctime>
#define EPS 1E-8
using namespace std;
typedef long long LL;
/****************************************************/
LL gcd(LL a,LL b)
{
return b==0?a:gcd(b,a%b);
}
int main()
{
LL t;
cin>>t;
while(t--)
{
LL n;
cin>>n;
LL a=n/2;
LL b=n-a;
while(gcd(a,b)>1)
{
a--;b++;
}
cout<<a*b<<endl;
}
}
1008 Pieces
貌似有很多胡搞的方法,不过第一眼看题还是想到了poj的那道dp,加入字符变成回文字符串。这个可比那题难多了,应该是个状态压缩dp。对于剩下多少字符没选是一种状态,然后判断相同字符进行dp。说实话,看着标程还是不会。这场的题太高能了,这都算简单题了。
/****************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <stack>
#include <map>
#include <queue>
#include <algorithm>
#include <ctime>
#define EPS 1E-8
#define MAXN 16
#define INF (~0U>>2)
using namespace std;
typedef long long LL;
/****************************************************/
int dp[1 << MAXN][MAXN][MAXN],n;
char str[MAXN + 10];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%s", str);
n = strlen(str);
for (int i = 0; i < n; i++)
{
for (int j = i; j < n; j++)
dp[0][i][j] = 0;
}
for (int rest = 1; rest < 1 << n; rest++)
{
//puts("ok");
for (int i = n - 1; i >= 0; i--)
{
for (int j = i; j < n; j++)
{
dp[rest][i][j] = INF;
if (i < j) dp[rest][i][j] = min(dp[rest][i][j - 1], dp[rest][i + 1][j]);
if (str[i] == str[j] && (rest >> j & 1) && (rest >> i & 1))
{
int tmp = rest & (~(1 << i)) & (~(1 << j));
if (tmp == 0)
dp[rest][i][j] = min(dp[rest][i][j], dp[tmp][i][j] + 1);
else
dp[rest][i][j] = min(dp[rest][i][j], dp[tmp][i][j]);
}
//cout << dp[rest][i][j] << endl;
}
}
for (int i = n - 1; i >= 0; i--)
{
for (int j = i; j < n; j++)
{
dp[rest][i][j] = min(dp[rest][i][j], dp[rest][0][n - 1] + 1);
}
}
}
printf("%d\n", dp[(1 << n) - 1][0][n - 1]);
}
}
1010 No Pain No Game
比赛的时候第二道研究的题,因为比较水,不会线段树和树状数组。所以结束之后自学了一天,然后看题还是不太懂。按照题解和标程敲了一遍,里面有一个技巧就是每次查询左端点到最后的最大值肯定是答案,因为在查询前后面的区间没有插入。等我仔细研究一下树状数组的具体用法再完善一下此题吧。
/****************************************************/
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <stack>
#include <map>
#include <queue>
#include <algorithm>
#include <ctime>
#define EPS 1E-8
#define MAXN 50010
using namespace std;
typedef long long LL;
/****************************************************/
int n,num[MAXN],to[MAXN],tmp[MAXN],ans[MAXN],tree[MAXN];
int lowbit(int x)
{
return x&(-x);
}
void add(int h,int num)
{
h=MAXN-1-h;
while(h<MAXN)
{
tree[h]=max(tree[h],num);
h+=lowbit(h);
}
}
int query(int h)
{
int ret=0;
h=MAXN-1-h;
while(h>0)
{
ret=max(ret,tree[h]);
h-=lowbit(h);
}
return ret;
}
struct Node
{
int l,r,num,flag;
}pa[500010];
bool cmp(Node a,Node b)
{
if(a.r!=b.r)
return a.r<b.r;
if(a.flag!=b.flag)
return a.flag<b.flag;
return a.l<b.l;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(tree,0,sizeof(tree));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
to[num[i]]=i;
}
int top=0;
for(int i=2;i<=n;i++)
{
int p=0;
for(int j=i;j<=n;j+=i)
{
tmp[p++]=to[j];
}
if(p==1) continue;
sort(tmp,tmp+p);
for(int j=0;j<p-1;j++)
{
pa[top].l=tmp[j];
pa[top].r=tmp[j+1];
pa[top].num=i;
pa[top].flag=-1;
top++;
}
}
int m;
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&pa[top].l,&pa[top].r);
pa[top].num=i;pa[top].flag=1;
top++;
}
sort(pa,pa+top,cmp);
for(int i=0;i<top;i++)
{
if(pa[i].flag<0)
add(pa[i].l,pa[i].num);
else if(pa[i].l==pa[i].r)
ans[pa[i].num]=0;
else
ans[pa[i].num]=max(1,query(pa[i].l));
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
}