题目传送门: 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>