1001 AND Minimum Spanning Tree (思维 二进制运算)
http://acm.hdu.edu.cn/showproblem.php?pid=6614
题意
给你1-n个数 让你建最小生成树 边的权值为两点按位与 求最小权值和 和 建发(最小字典序)
思路
字典序最小 那就连最小按位与为0的点 找的最小的0 该为1即可 对于全为1的点连在100..0上(如果不等于n,等于n的话连在1上 权值即为1)
代码
#include
using namespace std;
int a[50];
int n;
int f[200005*2];
int ok(int x)
{
int qw;
int qwe = x;
for(int i = 1;i <= 18;i++)
{
a[i] = x % 2;
x /= 2;
if(a[i] == 1) qw = i;
}
int ans = 0;
x = 1;
for(int i = 1;i <= qw;i++)
{
if(a[i] == 0) {ans += x;break;}
x *= 2;
}
if(f[ans]) return 1;
if(ans == 0&&qwe + 1 <= n) return qwe+1;
else if(ans == 0) return 1;
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
int x = 2;
int ans = 0;
for(int i = 1;;i++)
{
x *= 2;
if(x - 1 == n)
{
ans = 1;
break;
}
else if(x - 1 > n) break;
f[x-1] = 1;
}
printf("%d\n",ans);
printf("1");
for(int i = 3;i <= n;i++)
{
ans = ok(i);
printf(" %d",ans);
}
printf("\n");
}
return 0;
}
1003 Divide the Stones (思维)
http://acm.hdu.edu.cn/showproblem.php?pid=6616
题意
给你n个数1-n 让你分成k组 使每组数字和相等 输出分法
思路
If the total number of stones is a multiple of k, we can always divide the stones. Otherwise, we can’t.
If n/k is even, you can find solution quite easily.
If n/k is an odd number, we divide first 3k stones into k groups with exactly 3 stones and equal weight.
After that, you can divide remaining stones by the way you did when n/k is even.
Time complexity is O(n).
代码
#include
using namespace std;
typedef long long ll;
const int maxn = 1e5+100;
vector ans[maxn];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
ll n,k;
scanf("%lld%lld",&n,&k);
ll sum = n*(n+1)/2;
if(k == 1)
{
printf("yes\n");
for(int i = 1;i <= n;i++)
{
printf("%d ",i);
}
continue;
}
if(sum % k != 0)
{
printf("no\n");
continue;
}
ll qw = n / k;
printf("yes\n");
for(int i = 1;i <= k;i++) ans[i].clear();
if(qw % 2 == 0)
{
int id = 1;
for(int i = 1;i <= n/2;i++)
{
ans[id].push_back(i);
id++;
if(id > k) id = 1;
}
id = 1;
for(int i = n;i > n/2;i--)
{
ans[id].push_back(i);
id++;
if(id > k) id = 1;
}
}
else
{
for(int i = 1; i <= k; i++)
{
ans[i].push_back(i);
ans[i].push_back(k + (i + k / 2 - 1) % k + 1);
ans[i].push_back(2 * k + (1 + k) / 2 * 3 - i - ((i + k / 2 - 1) % k + 1));
}
int len = (n-3*k) / 2;
int id = 1;
for(int i = 3*k+1;i <= 3*k+len;i++)
{
ans[id].push_back(i);
id++;
if(id > k) id = 1;
}
id = 1;
for(int i = n;i > 3*k+len;i--)
{
ans[id].push_back(i);
id++;
if(id > k) id = 1;
}
}
for(int i = 1;i <= k;i++)
{
for(int j = 0;j < ans[i].size();j++)
{
printf("%d ",ans[i][j]);
}
printf("\n");
}
}
return 0;
}
1007 Just an Old Puzzle (定理)
http://acm.hdu.edu.cn/showproblem.php?pid=6620
题意
给你一个4*4的图 问你能不能在120步内移动到初始状态
思路
定理
代码
#include
using namespace std;
typedef long long ll;
int a[20];
int main()
{
int T;
scanf("%d",&T);
int p = 1;
while(T--)
{
p = 1;
for(int i = 1;i <= 4;i++)
{
for(int j = 1;j <= 4;j++)
{
int x;
scanf("%d",&x);
a[p++] = x;
}
}
if(a[16] != 0)
{
while(1)
{
for(int i = 1;i <= 16;i++)
{
if(a[i] == 0)
{
if(i + 4 <= 16)
{
swap(a[i],a[i+4]);
}
else
{
swap(a[i],a[i+1]);
}
}
}
if(a[16] == 0) break;
}
}
int num = 0;
for(int i = 1;i <= 15;i++)
{
for(int j = i + 1;j <= 15;j++)
{
if(a[i] > a[j]) num++;
}
}
if(num%2 == 0) printf("Yes\n");
else printf("No\n");
}
return 0;
}
1008 K-th Closest Distance (主席树)
http://acm.hdu.edu.cn/showproblem.php?pid=6621
题意
给你n个数 若干次询问 每次给你一个区间 问你第k接近q的数和q差多少
思路
强制在线 区间问题 主席树 二分答案 查询p-ans 到 p+ans范围内个数是否大于k
代码
#include
#include
#include
using namespace std;
const int MAX = 1e5+100;
struct Node {
int sum, l, r;
} tree[MAX * 40];
int root[MAX], cnt;
int data[MAX];
int n,m;
//离散化获得ID
//int get_id(int x) {
// return lower_bound(sorted.begin(), sorted.end(), x) - sorted.begin() + 1;
//}
void init() {
cnt = 0;
root[0] = 0;
}
//根据旧版本的线段树创建新线段树的节点
int create_node(int po) {
int idx = ++cnt;
tree[idx].sum = tree[po].sum + 1;
tree[idx].l = tree[po].l;
tree[idx].r = tree[po].r;
return idx;
}
void updata(int &o, int po, int l, int r, int pos) {
o = create_node(po);
if (l == r) return;
int m = (l + r) >> 1;
if (pos <= m) updata(tree[o].l, tree[po].l, l, m, pos);
else updata(tree[o].r, tree[po].r, m + 1, r, pos);
}
//二分查询
//int query(int s, int e, int l, int r, int k) {
// if (l == r) return l;
// int m = (l + r) >> 1;
// int sum = tree[tree[e].l].sum - tree[tree[s].l].sum;
// if (k <= sum) return query(tree[s].l, tree[e].l, l, m, k);
// else return query(tree[s].r, tree[e].r, m + 1, r, k - sum);
//}
int query(int s,int e,int l,int r,int x,int y)
{
if(l == x&&r == y)
return tree[e].sum - tree[s].sum;
int mid = (l + r) / 2;
if(y <= mid) return query(tree[s].l,tree[e].l,l,mid,x,y);
else if(x > mid) return query(tree[s].r,tree[e].r,mid+1,r,x,y);
else return query(tree[s].l,tree[e].l,l,mid,x,mid) + query(tree[s].r,tree[e].r,mid+1,r,mid+1,y);
}
int main() {
int T;
scanf("%d",&T);
while(T--)
{
n = read(),m = read();
for(int i = 1;i <= n;i++)
{
scanf("%d",&data[i]);
// sorted.push_back(data[i]);
}
// sort(sorted.begin(),sorted.end());
// sorted.erase(unique(sorted.begin(),sorted.end()),sorted.end());
// int num = sorted.size();
init();
for(int i = 1;i <= n;i++)
{
updata(root[i],root[i-1],1,1e6,data[i]);
}
int qw = 0;
while(m--)
{
int l,r,p,k;
scanf("%d%d%d%d",&l,&r,&p,&k);
l ^= qw,r ^= qw,p ^= qw,k ^= qw;
if(l > r) swap(l,r);
int ll = 0,rr = max(p,(int)1e6-p);
while(ll + 1 < rr)
{
int mid = (ll + rr) / 2;
int num = query(root[l-1],root[r],1,1e6,max(p-mid,(int)1),min(p+mid,(int)1e6));
if(num >= k)
{
rr = mid;
}
else ll = mid;
}
int num = query(root[l-1],root[r],1,1e6,max(p-ll,(int)1),min(p+ll,(int)1e6));
if(num >= k)
{
printf("%d\n",ll);
qw = ll;
}
else
{
printf("%d\n",rr);
qw = rr;
}
}
}
return 0;
}
1010 Minimal Power of Prime (思维)
http://acm.hdu.edu.cn/showproblem.php?pid=6623
题意
给你一个数n 问你因式分解后 素数的所有幂中最小的是多少
思路
暴力计算到n的(1/5)次方 剩下的最大不会超过5次方 枚举计算即可
代码
#include
using namespace std;
typedef long long ll;
const int N = 4000;
ll pri[N],top=0;
int vis[N];
ll po(ll a,int b)
{
ll ret=1;
while(b--)
ret*=a;
return ret;
}
int check(ll n,int k)
{
ll t=pow(n,1.0/k);
t-=5;
if(t<1)
t=1;
while(po(t+1,k)<=n)
t++;
return po(t,k)==n;
}
void solve(ll n)
{
int mi = 100000;
for(int i = 0;i < top&&pri[i] <= n;i++)
{
if(n % pri[i] == 0)
{
int num = 0;
while(n % pri[i] == 0)
{
num++;
n /= pri[i];
}
mi = min(mi,num);
}
}
if(n == 1) {printf("%d\n",mi);return ;}
for(int i = 4;i >= 2;i--)
{
if(check(n,i))
{
printf("%d\n",i);
return ;
}
}
printf("1\n");
}
int main()
{
for(int i = 2;i <= N;i++)
{
if(vis[i] == 0)
{
pri[top++] = i;
for(int j = i+i;j <= N;j+=i)
{
vis[j] = 1;
}
}
}
int T;
scanf("%d",&T);
while(T--)
{
ll n;
scanf("%lld",&n);
solve(n);
}
return 0;
}