A - Neon Sign
题意:n个点的完全图,每个顶点与其余顶点边的颜色分蓝、红两种。要求三边一样颜色的三角形的个数。
考虑暴力O(n^3)会T,所以试了一发反解(两边颜色不同就ans–),还是T了
题解:对于由不同色边组成的三角形,只可能有两条边同色,一条边不同色的情况。如果枚举一遍每一个点,记录从这个点连出的边中有多少条边的颜色不一样,总和记做 sum,那么对于任意一个不同色三角形,它的那条不同色边的两个端点会各算一次。所以不同色三角形个数就为sum/2。
#include <iostream>
#include <cstring>
using namespace std;
int n;
int a[1005],b[1005];
int main(){
ios::sync_with_stdio(0);
int T;
cin>>T;
while (T--){
int n,x;
cin>>n;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
int ans=0;
for (int i=1; i<=n-1; i++){
for (int j=i+1; j<=n; j++){
cin>>x;
if (x) {
a[i]++;
a[j]++;
}
else {
b[i]++;
b[j]++;
}
}
}
for (int i=1; i<=n; i++){
ans+=a[i]*b[i];
}
ans=n*(n-1)*(n-2)/6-ans/2;
cout<<ans<<endl;
}
return 0;
}
B - The Sum of the k-th Powers
C - Biorhythms
题意:人自出生起就有体力,情感和智力三个生理周期,分别为23,28和33天。一个周期内有一天为峰值。通常这三个周期的峰值不会是同一天。现在给出三个日期,分别对应于体力,情感,智力出现峰值的日期。然后再给出一个起始日期,要求从这一天开始,算出最少再过多少天后三个峰值同时出现。、
题解:中国剩余定理模版题,因为这题补了这方面的知识,详见中国剩余定理
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
ll a[4];
ll m[4]={23,28,33};
const int mod=21252;
ll extend_gcd(ll a, ll b, ll &x, ll &y) {
ll res=a;
if (b!=0) {
res=extend_gcd(b,a%b,y,x);
y-=(a/b)*x;
} else {
x=1;
y=0;
}
return res;
}
ll china(int len, ll *m, ll *a) {
ll M=1,w,d,x,y,ret=0;
for (int i=0; i<len; i++) M*=m[i];
for (int i=0; i<len; i++) {
w=M/m[i];
d=extend_gcd(m[i],w,x,y);
ret=(ret+y*w*a[i])%M;
}
return (M+ret%M)%M;
}
int main() {
//ios::sync_with_stdio(0);
ll d;
int cnt=1;
while (cin>>a[0]>>a[1]>>a[2]>>d) {
if(a[0]==-1 && a[1]==-1 && a[2]==-1 && d==-1)
break;
ll ans=(china(3,m,a)-d)%mod;
if (ans<=0) ans+=mod;
printf("Case %d: the next triple peak occurs in %lld days.\n",cnt++,ans);
}
return 0;
}
D - The Rotation Game
E - Strange Way to Express Integers
题意:给出k组 a r 每组代表 x ≡ r (mod a)
题解:(不互质)扩展中国剩余定理,其实跟中国剩余定理没关系 ,
详见扩展中国剩余定理
#include <iostream>
#include <cstdio>
typedef long long ll;
using namespace std;
ll m[60000],a[60000];
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
ll extend_gcd(ll a, ll b, ll &x, ll &y) {
ll res=a;
if (b!=0) {
res=extend_gcd(b,a%b,y,x);
y-=(a/b)*x;
} else {
x=1;
y=0;
}
return res;
}
ll exchina(ll n) {
ll m1=m[0],a1=a[0];
ll m2,a2,k1,k2,x0,g,c;
ll lcm=m[0];
for(int i=1; i<n; i++) {
m2=m[i];
a2=a[i];
c=a2-a1;
g=extend_gcd(m1,m2,k1,k2);
lcm=lcm*m[i]/gcd(lcm,m[i]);
if(c%g) return -1;
x0=k1*c/g;
ll t=m2/g;
x0=(x0%t+t)%t;
a1+=m1*x0;
m1=t*m1;
}
if (a1==0){
a1=1;
for (int i=0; i<n; i++)
a1=a1*m[i]/gcd(a1,m[i]);
}
return a1;
}
int main() {
ios::sync_with_stdio(0);
ll n;
while (cin>>n) {
for (int i=0; i<n; i++) {
cin>>m[i]>>a[i];
}
if (n==1) {
cout<<a[0]<<endl;
continue;
}
ll ans=exchina(n);
cout<<ans<<endl;
}
return 0;
}
F - Revenge of Fibonacci
字典树+高精度
题意:输入一个斐波那契数的前缀,求开头与所给前缀相同的最小斐波那契数的编号。
题解:题面给出最多查询位数是 40 位,为保证计算精度,每次计算取出前
50 位前缀。我们可以在处理询问前,先计算出前100000 个斐波那契数列的值并
存储,用字典树存储,加速前缀的查询效率,判断是否为前缀。
这题让我知道了关闭流同步会导致wa
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=8e6+5;
int nx[8000000][15];
int ed[8000000];
int cnt=1;
string sum(string a,string b) {
if (a.size()<b.size())
swap(a,b);
int i,j;
for (i=a.size()-1,j=b.size()-1; i>=0; i--,j--) {
a[i]=(char)(a[i]+(j>=0?b[j]-'0':0));
if (a[i]-'0'>=10) {
a[i]=(char)((a[i]-'0')%10+'0');
if(i) a[i-1]++;
else a='1'+a;
}
}
return a;
}
void insert(string s, int tol){
int pos=1;
int len=s.size();
ed[pos]=min(ed[pos],tol);
for (int i=0; i<len; i++){
int t=s[i]-'0';
if (!nx[pos][t]) nx[pos][t]=++cnt;
pos=nx[pos][t];
ed[pos]=min(ed[pos],tol);
}
}
bool find(string s){
int pos=1;
int len=s.size();
for (int i=0; i<len; i++){
int t=s[i]-'0';
if (!nx[pos][t]) return false;
pos=nx[pos][t];
}
cout<<ed[pos]-1<<endl;
return true;
}
int main() {
//ios::sync_with_stdio(0);
int x;
cin>>x;
string a="0",b="1";
memset(ed,0x3f,sizeof(ed));
insert(a,0);
insert(b,1);
for(int i=2; i<=100000; i++) {
string tmp=sum(a,b);
insert(tmp,i);
if(tmp.length()>50) {
tmp=tmp.substr(0,tmp.length()-1);
b=b.substr(0,b.length()-1);
}
a=b;
b=tmp;
}
for (int i=1; i<=x; i++) {
printf("Case #%d: ",i);
string s;
cin>>s;
if (s=="1") {
puts("0");
continue;
}
if (!find(s)) puts("-1");
}
return 0;
}
G - Counting Stars
H - Jacobi symbol
题意:求二次剩余 J(a,p)
题解:总结了一下二次剩余相关定理,详见二次剩余
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
ll mod_pow(ll x, ll n, ll mod){
ll res=1;
while (n>0){
if (n&1) res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res%mod;
}
int p[maxn];
bool isprime[maxn];
int cnt=0;
void sieve(){
for(int i=0;i<=maxn;i++) isprime[i]=true;
isprime[0]=isprime[1]=false;
for(int i=2; i<=maxn; i++){
if(isprime[i]){
p[cnt++]=i;
for(int j=2*i;j<=maxn;j+=i){
isprime[j]=false;
}
}
}
}
int getans(int a, int m){
if (a%m==0) return 0;
return mod_pow(a,(m-1)/2,m)==1?1:-1;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
int x,n;
sieve();
while (cin>>x>>n){
int ans=1;
if (!isprime[n]){
for (int i=0; i<cnt && p[i]<=n; i++){
if (n%p[i]) continue;
int tol=0;
while (n%p[i]==0){
tol++;
n/=p[i];
}
int t=getans(x,p[i]);
if (t==-1 && tol%2==0) t=1;
ans*=t;
}
}
else ans=getans(x,n);
cout<<ans<<endl;
}
return 0;
}