zoukankan      html  css  js  c++  java
  • 某5道CF水题

    1.PolandBall and Hypothesis

    题面在这里!

        大意就是让你找一个m使得n*m+1是一个合数。

        首先对于1和2可以特判,是1输出3,是2输出4。

        然后对于其他所有的n,我们都可以非常快的找到一个最小的与它互质的质数p(考虑反证法),并且满足p<n。

        这样就相当与解一个同余方程 n*m = p-1 (mod p) , 解出的m可以保证 n*m+1 是 p 的倍数,也就是合数了。

        又因为gcd(p,n)==1,所以这个方程肯定有解,直接求一个 n 在mod p意义下的逆元然后乘上 p-1 就行了。

         这个方法牛逼的地方就在它的复杂度(如果不算快速幂和n大了要用高精度的话)是比log还小的,所以n甚至可以出到 2^63 级别。

     (但这样就不好写checker了吧2333)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    int zs[10]={2,3,5,7,11,13,17,19,23,29},n,i;
    
    inline int ksm(int x,int y,const int ha){
    	int an=1;
    	for(;y;y>>=1,x=x*(ll)x%ha) if(y&1) an=an*(ll)x%ha;
    	return an; 
    }
    
    int main(){
    	scanf("%d",&n);
    	if(n==1) puts("3");
    	else if(n==2) puts("4");
    	else for(;i<10;i++) if(n%zs[i]){
    		const int ha=zs[i];
    		printf("%d
    ",(ha-1)*(ll)ksm(n%ha,ha-2,ha)%ha);
    		break;
    	}
    	return 0;
    }
    

    2.PolandBall and Game

    题面在这里!

        很裸很裸的一个贪心,肯定是优先选重叠的,所以hash一下直接贪就好啦QWQ

    #include<bits/stdc++.h>
    #define ll unsigned long long
    using namespace std;
    
    unordered_map<ll,int> mmp;
    int n,m,tot;
    ll now;
    char c;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	
    	for(int i=1;i<=n;i++){
    		for(c=getchar(),now=0;c!='
    ';c=getchar()) now=now*(ll)73+c-'a'+3ll;
    		if(!now){ i--; continue;}
    		mmp[now]=1;
    	}
    	for(int i=1;i<=m;i++){
    		for(c=getchar(),now=0;c!='
    ';c=getchar()) now=now*(ll)73+c-'a'+3ll;
    		if(!now){ i--; continue;}
    		if(mmp[now]) tot++;
    	}	
    	
    	n+=(tot&1);
    	puts(n>m?"YES":"NO");
    	
    	return 0;
    }
    

    3.PolandBall and Forest

    题面在这里!

        又是一道神仙题。

        可以证明同一颗树里面的p[]一定是点标号严格最小的直径中的一个端点,这个玩意还是画画图比较好理解。。。

        于是我们就找一找这种端点互相对应的直径数就好啦。

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=10005;
    
    int n,a[N],cnt;
    
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++) scanf("%d",a+i);
    	for(int i=1;i<=n;i++) if(a[i]>=i&&a[a[i]]==i) cnt++;
    	printf("%d
    ",cnt);
    	return 0;
    }
    

    4.PolandBall and Gifts

    题面在这里!

        把置换拆成环之后,可以发现一个位置不带礼物会影响环上它和它的后继,那么两种极值肯定是希望 影响尽量重叠 或者 尽量不重叠。

       

        最小化的话就是尽量重叠,可以发现当且仅当物品看成是环大小的背包可以凑出k的时候答案是k;否则就是k+1。

        直接背包肯定会凉凉啊,但是多重背包可以把每个物品的体积拆成 1 + 2 + 4 + ... + lef,偶数项都可以放到更大的体积的物品中去(因为 ∑每种物品的体积×个数 = N,所以不会出事),所以每种物品最多加两次,并且最多加sqrt(N)种不同的物品(想一想为什么),于是bitset一下复杂度刚刚好是 3*1e7,卡着过(虽然实际复杂度非常优秀)。

        最大化非常简单,直接贪心就好啦QWQ

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=1e6+5;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar());
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    bitset<N> B;
    int n,p[N],k,K,ans[2],lef,c[N];
    bool v[N];
    
    inline int getlen(int x){
    	int an=0;
    	for(;!v[x];x=p[x]) v[x]=1,an++;
    	return an;
    }
    
    inline void solve0(){
    	for(int i=1,now;i<=n;i++) if(!v[i]){
    		now=getlen(i),c[now]++;
    		lef+=now&1,now^=now&1;
    		if(K>=(now>>1)) K-=now>>1,ans[0]+=now;
    		else if(K) ans[0]+=K<<1,K=0;
    	}
    	if(K) ans[0]+=min(K,lef);
    }
    
    inline void solve1(){
    	B[0]=1;
    	for(int i=1;i<=n;i++) if(c[i]){
    		B|=B<<i,c[i]--;
    		if(c[i]&1) B|=B<<i;
    		c[i<<1]+=c[i]>>1;
    	}
    	ans[1]=B[k]?k:k+1;
    }
    
    int main(){
        n=read(),K=k=read();
        for(int i=1;i<=n;i++) p[i]=read();
        solve0(),solve1();
        printf("%d %d
    ",ans[1],ans[0]);
        return 0;
    }
    

    5.Fix a Tree

    题面在这里!

        首先原图肯定是若干基环树,我们的任务就是最后只留一个联通的基环树,并且环还得是自环。

        先看一看原图中有没有自环,如果有的话就随便找一个当根。

        然后用并查集维护联通性,如果i和p[i]已经在一个联通分量里的话,就把p[i]指向根,并且ans++。

        当然,如果原来就没有根的话那么就把i设为根,最后答案是一样的。

        可以证明答案总是 : 联通分量个数 - [原图中有没有自环]

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int N=200005;
    
    inline int read(){
    	int x=0; char ch=getchar();
    	for(;!isdigit(ch);ch=getchar());
    	for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    	return x;
    }
    
    void W(int x){ if(x>=10) W(x/10); putchar(x%10+'0');}
    
    int p[N],n,root,a[N],ans;
    
    int getf(int x){ return p[x]==x?x:(p[x]=getf(p[x]));}
    
    int main(){
    	n=read();
    	for(int i=1;i<=n;i++) p[i]=i,a[i]=read();
    	for(int i=1;i<=n;i++) if(a[i]==i){ root=i; break;}
    
    	for(int i=1,fa,fb;i<=n;i++) if(i!=root){
    		fa=getf(i),fb=getf(a[i]);
    		if(fa!=fb) p[fa]=fb;
    		else{
    			ans++;
    			if(root) a[i]=root;
    			else root=a[i]=i;
    		}
    	}
    
    	W(ans),puts("");
    	for(int i=1;i<=n;i++) W(a[i]),putchar(' ');
    	return 0;
    }
    
  • 相关阅读:
    js中级-函数封装
    js中级-11.7
    js中级-11.5
    js中级-11.2
    js中级-this
    js中级-作用域链
    10.23
    10.22
    10.19js
    10.18
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9293511.html
Copyright © 2011-2022 走看看