2016.4.17 南京理工大学校赛

题目传送门: https://icpc.njust.edu.cn/Contest/749/



A偷吃糖果

题意:给你两个字符串,将其中的连续的相同的字符串都缩成一个,问操作完毕后这两个字符串是否相等。

分析:简单题,暴力上吧。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
const int N=1005;
char s1[N],s2[N];
char ans1[N],ans2[N];
int len1,len2,sum1,sum2;
bool check()
{
	if (sum1!=sum2) return false;
	for (int i=0;i<sum1;i++){
		if (ans1[i]!=ans2[i]) return false;
	}
	return true;
}
int main()
{
	int t;
	scanf("%d",&t);
	while (t--)
	{
		scanf("%s%s",s1,s2); 
		len1=strlen(s1); len2=strlen(s2);
		sum1=sum2=0;
		for (int i=0;i<len1;i++){
			if (!i||s1[i]!=s1[i-1]){
				ans1[sum1++]=s1[i];
			}
		}
		for (int i=0;i<len2;i++){
			if (!i||s2[i]!=s2[i-1]){
				ans2[sum2++]=s2[i];
			}
		}
		if (check()) printf("Yes\n");
		else printf("No\n");
	}
	return 0;
}</span>



C  count_prime

题意:给一个区间[a,b]和一个整数n,问在区间中有多少个数字和n互质。

分析:数据范围n1e9,a,b1e15,题目可以转换成求区间[1,b]中和n互质的个数。

对n分解质因数,减去其中所有质因数的的倍数就好。

首先分解质因数,根据容斥原理,减去质因数的倍数,加上任意两个质因数的积的倍数,再减去任意三个质因数的积的倍数,etc。

由于分解后的质因数不会很多,所以直接DFS就好。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
long long factor[100],ans[100];
int tol,sum;
const int S=50;
long long mult_mod(long long a,long long b,long long c)
{
    a%=c; b%=c;
    long long ret=0;
    while(b)
    {
        if(b&1){ret+=a;ret%=c;}
        a<<=1;
        if(a>=c)a%=c;
        b>>=1;
    }
    return ret;
}
long long pow_mod(long long x,long long n,long long mod)//x^n%c
{
    if(n==1)return x%mod;
    x%=mod;
    long long tmp=x;
    long long ret=1;
    while(n)
    {
        if(n&1) ret=mult_mod(ret,tmp,mod);
        tmp=mult_mod(tmp,tmp,mod);
        n>>=1;
    }
    return ret;
}
bool check(long long a,long long n,long long x,long long t)
{
    long long ret=pow_mod(a,x,n);
    long long last=ret;
    for(int i=1;i<=t;i++)
    {
        ret=mult_mod(ret,ret,n);
        if(ret==1&&last!=1&&last!=n-1) return true;//ºÏÊý
        last=ret;
    }
    if(ret!=1) return true;
    return false;
}
bool Miller_Rabin(long long n)
{
    if(n<2)return false;
    if(n==2)return true;
    if((n&1)==0) return false;//żÊý
    long long x=n-1;
    long long t=0;
    while((x&1)==0){x>>=1;t++;}
    for(int i=0;i<S;i++)
    {
        long long a=rand()%(n-1)+1;//rand()ÐèÒªstdlib.hÍ·Îļþ
        if(check(a,n,x,t))
            return false;//ºÏÊý
    }
    return true;
}
long long gcd(long long a,long long b)
{
	if (a<0) return gcd(-a,b);
	if (!b) return a;
	if (!a) return b;
	return gcd(b,a%b);
}
long long Pollard_rho(long long x,long long c)
{
    long long i=1,k=2;
    long long x0=rand()%x;
    long long y=x0;
    while(1)
    {
        i++;
        x0=(mult_mod(x0,x0,x)+c)%x;
        long long d=gcd(y-x0,x);
        if(d!=1&&d!=x) return d;
        if(y==x0) return x;
        if(i==k){y=x0;k+=k;}
    }
}
void findfac(long long n)
{
    if(Miller_Rabin(n))
    {
        factor[tol++]=n;
        return;
    }
    long long p=n;
    while(p>=n)p=Pollard_rho(p,rand()%(n-1)+1);
    findfac(p);
    findfac(n/p);
}
long long tem;
void dfs(long long s,int x,long long a,int f)
{
	tem+=f*(a/s);
	if (x==sum-1) return;
	for (int i=x+1;i<sum;i++){
		if (s*ans[i]<=a) {
			dfs(s*ans[i],i,a,-f);
		}
	}
}
long long check(long long a,long long x)
{
	tem=0;
	for (int i=0;i<sum;i++){
		dfs(ans[i],i,a,1);
	}
	return a-tem;
}
int main()
{
    long long a,b,n;
    int t;
    scanf("%d",&t);
    while(t--)
    {
    	scanf("%lld%lld%lld",&a,&b,&n);
    	if (n==1) {
    		printf("%lld\n",b-a+1);
    		continue;
    	}
        tol=sum=0;
        findfac(n);
		sort(factor,factor+tol);
		for (int i=0;i<tol;i++){
			if (i==0||factor[i]!=factor[i-1]){
				ans[sum++]=factor[i];
			}
		}
		printf("%lld\n",check(b,n)-check(a-1,n));
    }
    return 0;
}</span>

D.triple

题意:给出一个整数n,表示1,2,...,n。从这n个数中任意选择3个不同的数字x,y,z,问x,y,z的最大公约数等于m的方案有多少种?(注意:(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)属于同一种方案)

分析:题目可以转换为,在区间[1,n/m]中选三个不同的数字并且最大公约数为1的方案数。

莫比乌斯反演的简单修改。注意去重的部分。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
bool check[MAXN+10];
long long prime[MAXN+10];
long long mu[MAXN+10];
void Moblus()
{
    memset(check,false,sizeof(check));
    mu[1] = 1;
    int tot = 0;
    for(int i = 2; i <= MAXN; i++) {
        if( !check[i] ) {
            prime[tot++] = i;
            mu[i] = -1;
        }
        for(int j = 0; j < tot; j++) {
            if(i * prime[j] > MAXN) break;
            check[i * prime[j]] = true;
            if( i % prime[j] == 0) {
                mu[i * prime[j]] = 0;
                break;
            }
            else  mu[i * prime[j]] = -mu[i];
        }
    }
}
int main()
{
    int T,n,m;
    long long ans1,ans2,ans3;
    Moblus();
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        n/=m;
        ans1=ans2=ans3=0; 
        for (int i = 1; i <= n;i++)
			ans1 += (long long)mu[i]*(n/i)*(n/i)*(n/i);
		for (int i = 1; i <= n;i++)
			ans3 += (long long)mu[i]*(n/i)*(n/i);
		ans3=(ans3-1)*3+1;
		printf("%lld\n",(ans1-ans3)/6);
    }
    return 0;
}</span>

F.sequence

题意:经典题目,《最少拦截系统》。

分析:参考hdu 1257

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5;
int a[N],l[N],r[N];
void DEL(int i)
{
	r[l[i]]=r[i];
	l[r[i]]=l[i];
}
int main()
{
	int t,ans,num,n;
	scanf("%d",&t);
	while (t--){
		scanf("%d",&n);
		for (int i=1;i<=n;i++) scanf("%d",&a[i]);
		for (int i=0;i<=n;i++) r[i]=i+1;
		for (int i=1;i<=n+1;i++) l[i]=i-1;
		ans=0;
		while (r[0]!=n+1){
			ans++;
			num=a[r[0]];
			for (int i=r[0];i!=n+1;i=r[i]){
				if (a[i]>=num){
					num=a[i];
					DEL(i);
				} 
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}</span>

G.琪露诺的算术教室

题意:给出一个非负整数A,将这个数字的最低位移动到最高位(原来的最高位变为次高位,次低位变成最低位),得到非负整数B,发现B恰好是A的k倍。现给出A的最低位的值n,和倍数k,求最小的非负整数B。


分析:n和k范围的范围都是0到9. 当n=0是,显然答案为0。除此之外,当k=0时无解,当k=1时答案=n.

其他情况模拟一遍即可。

需要注意的点,求出答案之后计算一下原答案,可能会有前导0的情况,此时为无解。

比如 n=1,k=2时,答案跑出来的结果是B=105263157894736842,那么A=052631578947368421,有前导0,所以实际上是无解。

当然,这道题直接打表也行。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
int ans[1005];
int main()
{
	int t,n,k,c,sum;
	scanf("%d",&t);
	while (t--)
	{
		scanf("%d%d",&n,&k);
		if (n==0) printf("0\n");
		else if (k==0) printf("-1\n");
		else if (k==1) printf("%d\n",n);
		else {
			ans[0]=n;
			c=0;
			for (sum=1;;sum++){
				ans[sum]=(ans[sum-1]*k+c)%10;
				c=(ans[sum-1]*k+c)/10;
				if (c==0&&ans[sum]==n) break;
			}
			if (ans[sum-1]==0) printf("-1\n");
			else {
				for (int i=sum;i>=1;i--){
					printf("%d",ans[i]);
				} printf("\n");
			}
		}
	}
	return 0;
}</span>


H.谁才是最强战舰!

题意:n堆石子,每次从一堆中取任意数量(不能不取),取到最后一颗者为负。

分析:anti-nim博弈(反尼姆博弈)模板题。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;  
int main(){  
    int t,n;  
    scanf("%d",&t);  
    while(t--){  
        scanf("%d",&n);  
        int k,cnt=0,ans=0;  
        while(n--){  
            scanf("%d",&k);  
            if(k>1) cnt++;  
            ans^=k;  
        }  
        if(cnt){  
            if(ans==0) puts("Meidikeji_Shijiediyi!");  
            else puts("Yamato_Saikou!");  
        }  
        else{  
            if(ans==0) puts("Yamato_Saikou!");  
            else puts("Meidikeji_Shijiediyi!");  
        }  
    }  
    return 0;  
}  </span>

J.water1

题意:一张二维的图片,从上方往下倒水,问至少倒多少水才能覆盖整个X轴。

分析:暴力水。

<span style="font-size:18px;">#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
long long a[N],b[N];
int main()
{
	int n;
	long long maxn,ans;
	while (~scanf("%d",&n))
	{
		if (n==0){
			printf("1\n");
			continue;
		}
		maxn=0;
		for (int i=1;i<=n;i++){
			scanf("%lld%lld",&a[i],&b[i]);
			maxn=max(maxn,a[i]+1);
		}
		ans=0;
		for (int i=1;i<=n;i++){
			ans+=(maxn-a[i])*b[i];
		}
		printf("%lld\n",ans);
		
	}
	return 0;
}</span>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值