2017 ACM/ICPC广西邀请赛
A Math Problem
题目链接
题意:给你一个n,求有多少个k满足
思路:预处理
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<string>
#include<cmath>
#include<stack>
#include<functional>
#include<bitset>
#define ll long long
#define maxn 100002
const int INF = 0x3f3f3f3f;
using namespace std;
ll num[22];
int s;
void init(){
ll i, j, t;
s = 1;
for(i = 1;i < 18;i++){
t = 1;
for(j = 0;j < i;j++){
if(1e18 / i >= t){
t *= i;
}
else{
return;
}
}
s = i;
num[i] = t;
}
}
int main(void){
init();
num[s + 1] = 1000000000000000002;
ll n, i;
while(scanf("%lld",&n)!=EOF){
for(i = 0;;i++){
if(n < num[i]){
printf("%lld\n",i - 1);
break;
}
}
}
return 0;
} B Color it
题目链接
题意:四种操作。0、初始化,清除操作。1、在坐标(x,y)上画上颜色c。2、计算(1,y1)到(x,y2)有多少种不同颜色。3、结束
思路:由于只有50种颜色,考虑建50棵线段树。采用动态开点,设立root数组表示第i种颜色的根节点编号。线段树上记录最小值,询问是否存在小于等于x。
#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
struct node{
int l,r,cnt;
node(){
l=r=cnt=0;
}
}T[maxn<<2];
int rt[55];
int tot=0;
int opr;
void update(int &rt,int l,int r,int pos,int val){
if(!rt){
rt=++tot;
T[rt].l=T[rt].r=0;
T[rt].cnt=val;
}
T[rt].cnt=min(T[rt].cnt,val);
if(l==r)
return;
int mid=(l+r)>>1;
if(pos<=mid) update(T[rt].l,l,mid,pos,val);
else update(T[rt].r,mid+1,r,pos,val);
}
bool query(int rt,int l,int r,int L,int R,int x){
if(!rt)
return false;
if(L<=l&&r<=R){
return T[rt].cnt<=x;
}
int mid=(l+r)>>1;
if(L<=mid&&query(T[rt].l,l,mid,L,R,x))
return true;
if(R>mid&&query(T[rt].r,mid+1,r,L,R,x))
return true;
return false;
}
void input(){
int x,y,c,l,r;
if(opr==0){
memset(rt,0,sizeof rt);
tot=0;
}else if(opr==1){
scanf("%d%d%d",&x,&y,&c);
update(rt[c],1,maxn-1,y,x);
}else if(opr==2){
scanf("%d%d%d",&x,&l,&r);
int ans=0;
for(int i=0;i<=50;i++){
if(query(rt[i],1,maxn-1,l,r,x))
ans++;
}
printf("%d\n",ans);
}
}
//void solve(){
//
//}
int main(){
while(scanf("%d",&opr)!=EOF){
if(opr==3)break;
input();
// solve();
}
} C Counting Stars
题目链接
题意:定义由两个三元环共享一条边的图为星星,求图上有多少子图可以构成星星
思路:对于三元环,有的做法判断。度数大向小连有向边,度数相同则编号小向编号大连有向边,然后对于每条边第第一个顶点的相连点标号,对第二个顶点相连点标号。 若存在一个三元环,将三元环的三边贡献都+1。对于每条边求C(n,2)。
为何是对于每条边求C(n,2),可能存在两个互不相交的子图都是要求的星型。
#include <bits/stdc++.h>
#define maxn 100005
typedef long long ll;
using namespace std;
int n,m;
int x[maxn<<1],y[maxn<<1];
int deg[maxn];
int vis[maxn];
int ans[maxn<<1];
int pos[maxn];
struct edge{
int to,index;
};
vector <edge>G[maxn];
void input(){
int i;
for(i=1;i<=m;i++){
scanf("%d%d",&x[i],&y[i]);
deg[x[i]]++;
deg[y[i]]++;
}
}
void solve(){
int i,j;
for(i=1;i<=m;i++){
if(deg[x[i]]>deg[y[i]])
G[y[i]].push_back((edge){x[i],i});
else if(deg[x[i]]<deg[y[i]])
G[x[i]].push_back((edge){y[i],i});
else
{
if(x[i]<y[i])
G[x[i]].push_back((edge){y[i],i});
else
G[y[i]].push_back((edge){x[i],i});
}
}
memset(vis,0,sizeof vis);
memset(pos,0,sizeof pos);
memset(ans,0,sizeof ans);
for(i=1;i<=m;i++){
int u=x[i],v=y[i];
for(j=0;j<G[u].size();j++){
vis[G[u][j].to]=i;
pos[G[u][j].to]=G[u][j].index;
}
for(j=0;j<G[v].size();j++)
{
if(vis[G[v][j].to]==i){
ans[i]++;
ans[G[v][j].index]++;
ans[pos[G[v][j].to]]++;
}
}
}
ll ANS=0;
for(i=1;i<=m;i++)
ANS+=1ll*ans[i]*(ans[i]-1)/2;
printf("%lld\n",ANS);
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++)
G[i].clear();
memset(deg,0,sizeof deg);
input();
solve();
}
}
/*
8 10
1 2
2 3
3 4
1 4
1 3
5 6
6 7
7 8
5 8
5 7
*/ D Covering
题目链接
题意:给你一个n,求有多少种方式12和21的毯子铺4n的空间
思路:zl递推出规律,建立了1616的矩阵快速幂,T了。用BM线性递推输入数据过了。。
正解的规律是dp[4]=dp[3]+5*dp[2]+dp[1]-dp[0]
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
// head
ll _,n;
namespace linear_seq {
const int N=10010;
ll res[N],base[N],_c[N],_md[N];
vector<int> Md;
void mul(ll *a,ll *b,int k) {
rep(i,0,k+k) _c[i]=0;
rep(i,0,k) if (a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;
for (int i=k+k-1;i>=k;i--) if (_c[i])
rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;
rep(i,0,k) a[i]=_c[i];
}
int solve(ll n,VI a,VI b) { // a 系数 b 初值 b[n+1]=a[0]*b[n]+...
// printf("%d\n",SZ(b));
ll ans=0,pnt=0;
int k=SZ(a);
assert(SZ(a)==SZ(b));
rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;
Md.clear();
rep(i,0,k) if (_md[i]!=0) Md.push_back(i);
rep(i,0,k) res[i]=base[i]=0;
res[0]=1;
while ((1ll<<pnt)<=n) pnt++;
for (int p=pnt;p>=0;p--) {
mul(res,res,k);
if ((n>>p)&1) {
for (int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;
rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;
}
}
rep(i,0,k) ans=(ans+res[i]*b[i])%mod;
if (ans<0) ans+=mod;
return ans;
}
VI BM(VI s) {
VI C(1,1),B(1,1);
int L=0,m=1,b=1;
rep(n,0,SZ(s)) {
ll d=0;
rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;
if (d==0) ++m;
else if (2*L<=n) {
VI T=C;
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
L=n+1-L; B=T; b=d; m=1;
} else {
ll c=mod-d*powmod(b,mod-2)%mod;
while (SZ(C)<SZ(B)+m) C.pb(0);
rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;
++m;
}
}
return C;
}
int gao(VI a,ll n) {
VI c=BM(a);
c.erase(c.begin());
rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;
return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));
}
};
int main() {
while (~scanf("%lld",&n)) {
vector<int>v;
v.push_back(1);//前几项
v.push_back(5);
v.push_back(11);
v.push_back(36);
v.push_back(95);
v.push_back(281);
v.push_back(781);
v.push_back(2245);
v.push_back(6336);
v.push_back(18061);
v.push_back(51205);
v.push_back(145601);
v.push_back(413351);
v.push_back(1174500);
v.push_back(3335651);
v.push_back(9475901);
//输入n ,输出第n项的值
printf("%d\n",linear_seq::gao(v,n-1));
}
}
E CS Course
题目链接
题意:给出n个数字,q次查询,查询除了第ai个数剩余所有数的与值、或值、异或值。
思路:前缀+后缀
#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,q;
int a[maxn];
int preand[maxn],sufand[maxn];
int prexor[maxn],sufxor[maxn];
int preor[maxn],sufor[maxn];
void input(){
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
preand[1]=prexor[1]=preor[1]=a[1];
for(int i=2;i<=n;i++){
preand[i]=preand[i-1]&a[i];
prexor[i]=prexor[i-1]^a[i];
preor[i]=preor[i-1]|a[i];
}
sufand[n]=sufxor[n]=sufor[n]=a[n];
for(int i=n-1;i>1;i--){
sufand[i]=sufand[i+1]&a[i];
sufxor[i]=sufxor[i+1]^a[i];
sufor[i]=sufor[i+1]|a[i];
}
}
void solve(){
int i,index;
for(i=1;i<=q;i++){
scanf("%d",&index);
int a=index-1;
int b=index+1;
if(a<1)
printf("%d %d %d\n",sufand[index+1],sufor[index+1],sufxor[index+1]);
else if(b>n)
printf("%d %d %d\n",preand[index-1],preor[index-1],prexor[index-1]);
else
printf("%d %d %d\n",preand[index-1]&sufand[index+1],preor[index-1]|sufor[index+1],prexor[index-1]^sufxor[index+1]);
}
}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
input();
solve();
}
} F Destroy Walls
题目链接
题意:给出n个城市,存在m座墙,第i座墙连接着ui城市和vi城市,求国王希望到达城市每一个地方所需要的拆墙的最少费用,以及拆多少座
思路:求最大生成树
#include <bits/stdc++.h>
#define maxn 100005
typedef long long ll;
using namespace std;
int n,m;
struct edge{
int from,to,cost;
};
bool cmp(edge a,edge b){
return a.cost>b.cost;
}
edge G[maxn<<1];
int fa[maxn];
ll sum;
void init(int n){
for(int i=1;i<=n;i++)
fa[i]=i;
}
int find(int x){
return x==fa[x]?x:fa[x]=find(fa[x]);
}
void mix(int x,int y){
int fx=find(x);
int fy=find(y);
fa[fx]=fy;
}
void input(){
init(n);
int i,x,y;
for(i=1;i<=n;i++){
scanf("%d%d",&x,&y);
}
int u,v,w;
sum=0;
for(i=1;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
G[i].from=u;
G[i].to=v;
G[i].cost=w;
sum+=G[i].cost;
}
}
void solve(){
sort(G+1,G+1+m,cmp);
ll ans=0;
int tot=0;
for(int i=1;i<=m;i++){
if(find(G[i].from)!=find(G[i].to)){
ans+=G[i].cost;
tot++;
mix(G[i].from,G[i].to);
}
}
printf("%lld %lld\n",m-tot,sum-ans);
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
input();
solve();
}
} G Duizi and Shunzi
题目链接
题意:给出n张牌,求能组成最多的对子或者顺子个数。
思路:对子优于顺子,特判顺子的一种情况
#include <bits/stdc++.h>
#define maxn 1000005
using namespace std;
int n;
int t[maxn];
void input(){
int i,a;
for(i=1;i<=n;i++){
scanf("%d",&a);
t[a]++;
}
}
void solve(){
int ans=0;
int i;
for(i=1;i<=1000000;i++){
if(t[i]>=2){
ans+=t[i]/2;
t[i]=t[i]&1;
}
while(i+2<=1000000&&t[i]&&t[i+1]%2&&t[i+2]){
t[i]--;
t[i+1]--;
t[i+2]--;
ans++;
}
}
printf("%d\n",ans);
}
int main(){
while(scanf("%d",&n)!=EOF){
memset(t,0,sizeof t);
input();
solve();
}
} J Query on A Tree
[题目链接](http://acm.hdu.edu.cn/showproblem.php?pid=6191) 题意:q次查询,给出一棵树,求结点u子树下值与x最大异或值 思路:通过DFS序建立可持久化字典树,在可持久化字典树中查询#include <bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,q;
int v[maxn];
vector <int>G[maxn];
int rt[maxn];
struct Persistent_Trie {
int tot;
int ch[maxn * 32][2];//开logn+2倍
int sum[maxn * 32];
void init() {
tot = 0;
memset(ch, 0, sizeof(ch));
memset(sum, 0, sizeof(sum));
}
void insert(int &x, int y, int val) {
int sta;
int t;
x = sta = ++tot;
for (int i = 30; i >= 0; i--) {
ch[sta][0] = ch[y][0];
ch[sta][1] = ch[y][1];
sum[sta] = sum[y] + 1;
t = val & (1 << i); t >>= i;
y = ch[y][t];
ch[sta][t] = ++tot;
sta = ch[sta][t];
}
sum[sta] = sum[y] + 1;
}
int query(int x, int y, int val) {
int res = 0;
for (int i = 30; i >= 0; i--) {
int t = val & (1 << i); t >>= i;
if (sum[ch[y][t ^ 1]] - sum[ch[x][t ^ 1]]) {
res += 1 << i;
y = ch[y][t ^ 1];
x = ch[x][t ^ 1];
}
else {
y = ch[y][t];
x = ch[x][t];
}
}
return res;
}
}pt;
int dfs_num[maxn];
int L[maxn],R[maxn];
int cnt;
void dfs(int x,int fa){
L[x]=++cnt;
dfs_num[cnt]=x;
for(int i=0;i<G[x].size();i++){
if(G[x][i]==fa)continue;
dfs(G[x][i],x);
}
R[x]=cnt;
}
void input(){
pt.init();
cnt=0;
int i,u,x;
for(i=1;i<=n;i++){
scanf("%d",&v[i]);
G[i].clear();
}
for(i=2;i<=n;i++){
scanf("%d",&x);
G[x].push_back(i);
}
dfs(1,-1);
for(i=1;i<=cnt;i++){
pt.insert(rt[i],rt[i-1],v[dfs_num[i]]);
}
for(i=1;i<=q;i++){
scanf("%d%d",&u,&x);
printf("%d\n",pt.query(rt[L[u]-1],rt[R[u]],x));
}
}
//void solve(){
//
//}
int main(){
while(scanf("%d%d",&n,&q)!=EOF){
input();
// solve();
}
}
京公网安备 11010502036488号