第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)

L Let's Play Curling

分析:

转换一下就是 找每两个b之间 最多有多少个a

先离散化 再树状数组维护一下就好

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
const int maxn=2e5+5;
int n,m,cnt,ans;
int a[maxn],b[maxn],t[maxn],tr[maxn];
void upd(int x){
	while(x<=maxn)tr[x]++,x+=lowbit(x);
}
int query(int x){
	int res=0;
	while(x)res+=tr[x],x-=lowbit(x);
	return res;
}
void solve();
int main(){
	int T;
	cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
	scanf("%d%d",&n,&m);
	ans=0;cnt=0;
	memset(tr,0,sizeof(tr));
	for(int i=1;i<=n;i++)scanf("%d",&a[i]),t[++cnt]=a[i];
	for(int i=1;i<=m;i++)scanf("%d",&b[i]),t[++cnt]=b[i];
	b[0]=t[++cnt]=0,b[m+1]=t[++cnt]=1e9+7;
	sort(t+1,t+1+cnt);
	int len=unique(t+1,t+1+cnt)-t-1;
	for(int i=1;i<=n;i++){
		int id=lower_bound(t+1,t+1+len,a[i])-t;
		a[i]=id,upd(a[i]);
	}
	for(int i=0;i<=m+1;i++){
		int id=lower_bound(t+1,t+1+len,b[i])-t;
		b[i]=id;
	}
	sort(b,b+2+m);
	for(int i=1;i<=m+1;i++)
	ans=max(ans,query(b[i]-1)-query(b[i-1]));
	if(!ans)cout<<"Impossible"<<endl;
	else cout<<ans<<endl;
}

F.Fireworks

分析:

式子很好列出 关键在于我们担心计算的时候会掉精度 但是最后打出来貌似不会掉

注意点:因为是要求整数 但是三分只有在小数的时候才能准确找到峰值 所以三分整数最终需要判断+1和-1的值

同样也可以三分小数 最终在小数前后位置找

#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
double n,m,p;
void solve();
double calc(int x){
	return (x*n+m)/(1-pow((10000-p)/10000,x));
}
int main(){
	int T;
	cin>>T;
	while(T--)solve();
     return 0;
}
void solve(){
	cin>>n>>m>>p;
	int l=1,r=1e9,ans;
	while(l<=r){
		int mid=(l+r)/2;
		int midd=(l+mid)/2;
		if(calc(mid)-calc(midd)>=1e-8)ans=midd,r=mid-1;
		else l=midd+1;
	}
	int res;
	if(calc(ans)-calc(ans-1)>=1e-8)res=ans-1;
	if(calc(ans)-calc(ans+1)>=1e-8)ans++;
	if(calc(ans)-calc(res)>=1e-8)ans=res;
	printf("%.6lf\n",calc(ans));
}

K Co-prime Permutation

签到题

E Evil Coordinate

分析:

很明显 只要障碍不在终点 或者只能朝x轴方向走(只能朝y轴方向走)并且一定会经过障碍点

其他情况一定是能构造出一个方案 使得路径不经过障碍点

分情况写起来很麻烦

题解给出了偷懒的智慧

完全用不着分类讨论

可以证明存在一种答案,使得相同的方向是连续排在一起的(按原字符串中有 1/2/3/4 种字母进行分类讨论)

枚举 UDLR 的 24 种排列即可

只要把所有情况都列出来 再判断即可

总结出经验 遇到分类讨论构造的题目 如果在数据范围允许的情况 可以遍历所有的构造方案

#include<bits/stdc++.h>
using namespace std;
int t,x,y,dx[]={0,0,-1,1},dy[]={1,-1,0,0},dd[200],c[4];
string s,ans,a="UDLR";
void solve()
{
	memset(c,0,sizeof c);
	scanf("%d%d",&x,&y);
	cin>>s;
	for(auto ch:s)c[dd[ch]]++;
	int xx=c[3]-c[2],yy=c[0]-c[1];
	if((xx==x&&yy==y)||(x==0&&y==0)){puts("Impossible");return;}
	int q[4]={0,1,2,3};
	do
	{
		xx=0,yy=0;
		ans="";
		for(int i=0;i<4;i++)
		{
			int p=q[i];
			for(int j=0;j<c[p];j++)
			{
				ans+=a[p];
				xx+=dx[p];
				yy+=dy[p];
				if(xx==x&&yy==y)goto End;
			}
		}
		cout<<ans<<endl;
		return;
		End:;
	}while(next_permutation(q,q+4));
	puts("Impossible");
}
int main()
{
	for(int i=0;i<4;i++)dd[a[i]]=i;
	scanf("%d",&t);
	while(t--)solve();
	return 0;
}

M Monster Hunter

分析:

很好分析的一道树形dp问题

因为相连点会造成影响 所以设置dp数组的时候多开一维 表示该点选择与否

dp[u][k][1] 表示u子树选择k个点 并且u选择的最小值

dp[u][k][0]表示u子树选择k个点 并且u不选择的最小值

不选择的点默认只能用魔法消掉

注意点:一开始一直觉得dfs里面两重循环会爆掉 但是实际上这个题目不会

在剪枝的条件下 具体复杂度肯定比三方小很多 比平方要大些

上下限都需要剪枝 不剪枝会TLE!!!!!!

总结一下就是:在n方的复杂度下是能够进行树上背包的 但是必须上下限都得剪枝

#include<bits/stdc++.h>
using namespace std;
int tot,g[2001],sz[2001],a[2001];
long long dp[2001][2001][2];
struct edge{
	int to,next;
}e[1000001];
void add(int a,int b)
{
	tot++;
	e[tot].to=b;
	e[tot].next=g[a];
	g[a]=tot;
}
void dfs(int x)
{
	sz[x]=1;
	dp[x][1][0]=a[x];
	dp[x][0][1]=0;
	for(int i=g[x];i;i=e[i].next)
	{
		dfs(e[i].to);
		sz[x]+=sz[e[i].to];
		for(int j=sz[x];j>=0;j--)
		{
			int di=max(0,j-sz[x]+sz[e[i].to]);//上下限都需要剪枝
			for(int k=min(j,sz[e[i].to]);k>=di;k--)
			{
				dp[x][j][0]=min(dp[x][j][0],dp[x][j-k][0]+min(dp[e[i].to][k][0]+a[e[i].to],dp[e[i].to][k][1]));
				dp[x][j][1]=min(dp[x][j][1],dp[x][j-k][1]+min(dp[e[i].to][k][0],dp[e[i].to][k][1]));
				//cout<<j<<" "<<k<<endl;
			}
		}
	}
}
signed main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n;
		scanf("%d",&n);
		for(int i=0;i<=n;i++)
		for(int j=0;j<=n;j++)
		dp[i][j][0]=dp[i][j][1]=1e18;
		for (int i=1;i<=n;i++)
		g[i]=0;tot=0;
		for(int i=2;i<=n;i++)
		{
			int x;scanf("%d",&x);
			add(x,i);
		}
		for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
		dfs(1);
		for(int i=n;i>=0;i--)
		{
			printf("%lld ",min(dp[1][i][0],dp[1][i][1]));
		}
		puts("");
	}
	return 0;
} 	

H Harmonious Rectangle

给你一个n*m的矩阵,每个点都可以取三种颜色。问你有多少种染色方法可以使得矩阵中至少一对(x1,y1)与(x2,y2)满足下列式子。

(a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||(a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2]))

分析:

其实很好想到 当n m 足够大的时候 一定是存在幽默矩阵的

考虑在矩阵中选择任意两行a和b

a1 a2 a3 a4 a5 a6 ......
b1 b2 b3 b4 b5 b6 ......

可知(a1,b1)有3*3=9种组合方式。根据鸽笼原理,或者直接动脑子想想,可以想到当列数>9时,一定存在另一组(ai,bi)与(a1,b1)相同。同理,当行数>9时,一定存在两组相同的列。所以可以分类讨论:

if n=1 || m=1 ,必为0

else if n>9 || m>9,结果为pow(3,n*m)

else 在9*9范围内,可以DFS剪枝搜索,然后把结果打个表。

打表

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

ll mod_mul(ll a, ll b, ll n) {
  a %= n;  //优化后只要在开头模一次,其他的地方用if,效率提升近一倍
  b %= n;
  ll res = 0;
  while (b) {
    if (b & 1) {
      res += a;
      if (res > n) res -= n;
    }
    a += a;
    if (a > n) a -= n;
    b /= 2;  //没开o2的话要换成b>>=1
  }
  return res;
}

ll mod_exp(ll a, ll b, ll n) {
  ll res = 1;
  a = a % n;
  while (b) {
    if (b & 1) res = mod_mul(res, a, n);
    a = mod_mul(a, a, n);
    b /= 2;
  }
  return res;
}

const ll MOD = 1e9 + 7;
const int MAXN = 12;
int a[MAXN][MAXN];
int n, m;
long long gcnt;

void get_next() {
  const static int base = 3;
  int carry = 1;
  for (int i = n - 1; i >= 0; i--) {
    for (int j = m - 1; j >= 0; j--) {
      a[i][j] += carry;
      carry = 0;
      if (a[i][j] >= base) {
        carry = a[i][j] / base;
        a[i][j] %= base;
      }
    }
  }
}

void print() {
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
      printf("%d ", a[i][j]);
    }
    printf("\n");
  }
  printf("\n");
}

bool check() {
  for (int y1 = 0; y1 < n; y1++) {
    for (int x1 = 0; x1 < m; x1++) {
      for (int y2 = y1 + 1; y2 < n; y2++) {
        for (int x2 = x1 + 1; x2 < m; x2++) {
          if ((a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||
              (a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2]))
            return true;
        }
      }
    }
  }
  return false;
}

void dfs(int xx, int yy) {
  for (int color = 0; color < 3; color++) {
    int x2 = xx;
    int y2 = yy;
    a[y2][x2] = color;
    bool flag = true;
    for (int y1 = 0; y1 < y2 && flag; y1++) {
      for (int x1 = 0; x1 < x2 && flag; x1++) {
        if ((a[y1][x1] == a[y2][x1] && a[y1][x2] == a[y2][x2]) ||
            (a[y1][x1] == a[y1][x2] && a[y2][x1] == a[y2][x2])) {
          flag = false;
          gcnt +=
              mod_exp(3LL, (1LL * (n - 1 - y2) * (m) + (m - 1) - x2), MOD);
          gcnt %= MOD;
        }
      }
    }
    if (flag) {
      x2++;
      if (x2 >= m) {
        x2 = 0;
        y2++;
        if (y2 >= n){
          continue;
        }
      }
      dfs(x2, y2);
    }
  }
  a[yy][xx]=-1;
}

ll solve_dfs(){
  gcnt=0;
  dfs(0,0);
  return gcnt;
}

int solve_exhaust() {
  int p = pow(3, n * m);
  int cnt = 0;
  for (int i = 0; i < p; i++) {
    if (check()) {
      cnt++;
      // print();
    }
    // print();
    get_next();
  }
  return cnt;
}

int main() {

  for(n =1; n<=9;n++){
    for(m=1;m<=9;m++){
      if(m==1||n==1) printf("0, ");
      else{
        memset(a,0,sizeof(a));
        printf("%lld, ",solve_dfs());
        //printf("%lld, ",solve_exhaust());
      }
    }
    printf("\n");
  }
  return 0;


}

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 1e9+7;
int n,m;

ll mod_mul(ll a, ll b, ll n) {
  a %= n;  //优化后只要在开头模一次,其他的地方用if,效率提升近一倍
  b %= n;
  ll res = 0;
  while (b) {
    if (b & 1) {
      res += a;
      if (res > n) res -= n;
    }
    a += a;
    if (a > n) a -= n;
    b /= 2;  //没开o2的话要换成b>>=1
  }
  return res;
}

ll mod_exp(ll a, ll b, ll n) {
  ll res = 1;
  a = a % n;
  while (b) {
    if (b & 1) res = mod_mul(res, a, n);
    a = mod_mul(a, a, n);
    b /= 2;
  }
  return res;
}

ll dat[9][9]={0, 0, 0, 0, 0, 0, 0, 0, 0, 
0, 15, 339, 4761, 52929, 517761, 4767849, 43046721, 387420489, 
0, 339, 16485, 518265, 14321907, 387406809, 460338013, 429534507, 597431612, 
0, 4761, 518265, 43022385, 486780060, 429534507, 792294829, 175880701, 246336683, 
0, 52929, 14321907, 486780060, 288599194, 130653412, 748778899, 953271190, 644897553, 
0, 517761, 387406809, 429534507, 130653412, 246336683, 579440654, 412233812, 518446848, 
0, 4767849, 460338013, 792294829, 748778899, 579440654, 236701429, 666021604, 589237756, 
0, 43046721, 429534507, 175880701, 953271190, 412233812, 666021604, 767713261, 966670169, 
0, 387420489, 597431612, 246336683, 644897553, 518446848, 589237756, 966670169, 968803245};

int main() {
  int T;
  scanf("%d",&T);
  while(T--){
    scanf("%d%d",&n,&m);
    if(n==1||m==1){
      printf("0\n");
    }
    else if(n<=9||m<=9){
      n--;
      m--;
      printf("%lld\n",dat[n][m]%MOD);
    }
    else{
      printf("%lld\n",mod_exp(3,1LL*n*m,MOD));
    }
  }
  return 0;
}

posted @ 2022-11-03 13:10  wzx_believer  阅读(172)  评论(0)    收藏  举报